diff --git a/.gitignore b/.gitignore index c02aa6f6..f24b914b 100644 --- a/.gitignore +++ b/.gitignore @@ -49,7 +49,8 @@ platform/wiiu/* *.d *.so *.os - +*.rpx +*.3dsx # QT project files *.config *.creator diff --git a/demos/2d/rubegoldberg/.fscache b/demos/2d/rubegoldberg/.fscache new file mode 100644 index 00000000..50c0d2b3 --- /dev/null +++ b/demos/2d/rubegoldberg/.fscache @@ -0,0 +1,16 @@ +::res://::1705781638 +ball.xml::PackedScene::1705781638:: +box.xml::PackedScene::1705781638:: +domino.xml::PackedScene::1705781638:: +icon.png::ImageTexture::1705781638:: +pendulum.xml::PackedScene::1705781638:: +platform.xml::PackedScene::1705781638:: +rubegoldberg.xml::PackedScene::1705781638:: +seesaw.xml::PackedScene::1705781638:: +::res://art::1705781638 +bowling_ball.png::ImageTexture::1705781638:: +box.png::ImageTexture::1705781638:: +domino.png::ImageTexture::1705781638:: +platform.png::ImageTexture::1705781638:: +seesaw_base.png::ImageTexture::1705781638:: +seesaw_top.png::ImageTexture::1705781638:: diff --git a/demos/3d/balls/.fscache b/demos/3d/balls/.fscache index 804b241e..f7cb1aad 100644 --- a/demos/3d/balls/.fscache +++ b/demos/3d/balls/.fscache @@ -1,5 +1,10 @@ +<<<<<<< HEAD +::res://::1708862929 +char_controller.gd::GDScript::1708780813:: +======= ::res://::1710360441 char_controller.gd::GDScript::1710360441:: +>>>>>>> fbdd36df3a8b2e204567fa7fd666453ee94e0c0c cube.scn::PackedScene::1705843654::scene_3d<>Models/cube.dae<>466036871213f4c3460df5cc83c6a860<>1682196562 floor.scn::PackedScene::1705844193::scene_3d<>Models/floor.dae<>b125887aa8250cd928758a60a3a1bfb5<>1682251078 icon.png::ImageTexture::1705843536:: diff --git a/demos/3d/fixed_materials/.fscache b/demos/3d/fixed_materials/.fscache new file mode 100644 index 00000000..30958d25 --- /dev/null +++ b/demos/3d/fixed_materials/.fscache @@ -0,0 +1,14 @@ +::res://::1705781638 +brick_color.png::ImageTexture::1705781638:: +brick_detail.png::ImageTexture::1705781638:: +brick_detail_emission.png::ImageTexture::1705781638:: +brick_detail_glow.png::ImageTexture::1705781638:: +brick_emission.png::ImageTexture::1705781638:: +brick_normal.png::ImageTexture::1705781638:: +fixed_materials.scn::PackedScene::1705781638::scene_3d<>./boxsphere.dae<>97feba9c1b870d4caf1d354f6adcb5db<>0 +icon.png::ImageTexture::1705781638:: +refmap.png::ImageTexture::1705781638:: +rim.png::ImageTexture::1705781638:: +rocky_specular.png::ImageTexture::1705781638:: +s.xml::Mesh::1705781638:: +tournesol.png::ImageTexture::1705781638:: diff --git a/demos/3d/sat_test/.fscache b/demos/3d/sat_test/.fscache new file mode 100644 index 00000000..b5e549c3 --- /dev/null +++ b/demos/3d/sat_test/.fscache @@ -0,0 +1,7 @@ +::res://::1705781638 +box.scn::PackedScene::1705781638::scene_3d<>./shapes.dae<>53bcfe8d39f1cc21dd4552d41b542c80<>1705781638 +capsule.scn::PackedScene::1705781638::scene_3d<>./shapes.dae<>53bcfe8d39f1cc21dd4552d41b542c80<>1705781638 +convex.scn::PackedScene::1705781638::scene_3d<>./shapes.dae<>53bcfe8d39f1cc21dd4552d41b542c80<>1705781638 +sat_test.xml::PackedScene::1705781638:: +shapes.scn::PackedScene::1705781638::scene_3d<>./shapes.dae<>53bcfe8d39f1cc21dd4552d41b542c80<>1705781638 +sphere.scn::PackedScene::1705781638::scene_3d<>./shapes.dae<>53bcfe8d39f1cc21dd4552d41b542c80<>1705781638 diff --git a/demos/3d/simple/.fscache b/demos/3d/simple/.fscache new file mode 100644 index 00000000..a6b02d80 --- /dev/null +++ b/demos/3d/simple/.fscache @@ -0,0 +1,2 @@ +::res://::1708965924 +icon.png::ImageTexture::1708965924:: diff --git a/demos/3d/simple/cube.dae b/demos/3d/simple/cube.dae new file mode 100644 index 00000000..d9293d60 --- /dev/null +++ b/demos/3d/simple/cube.dae @@ -0,0 +1,101 @@ + + + + + Blender User + Blender 2.80.75 commit date:2019-07-29, commit time:14:47, hash:f6cb5f54494e + + 2024-02-26T17:50:03 + 2024-02-26T17:50:03 + + Z_UP + + + + + + + + 0 0 0 1 + + + 0.8 0.8 0.8 1 + + + 1.45 + + + + + + + + + + + + + + + + + 1 1 1 1 1 -1 1 -1 1 1 -1 -1 -1 1 1 -1 1 -1 -1 -1 1 -1 -1 -1 + + + + + + + + + + 0 0 1 0 -1 0 -1 0 0 0 0 -1 1 0 0 0 1 0 + + + + + + + + + + 0.625 0 0.375 0.25 0.375 0 0.625 0.25 0.375 0.5 0.375 0.25 0.625 0.5 0.375 0.75 0.375 0.5 0.625 0.75 0.375 1 0.375 0.75 0.375 0.5 0.125 0.75 0.125 0.5 0.875 0.5 0.625 0.75 0.625 0.5 0.625 0 0.625 0.25 0.375 0.25 0.625 0.25 0.625 0.5 0.375 0.5 0.625 0.5 0.625 0.75 0.375 0.75 0.625 0.75 0.625 1 0.375 1 0.375 0.5 0.375 0.75 0.125 0.75 0.875 0.5 0.875 0.75 0.625 0.75 + + + + + + + + + + + + + + + 4 0 0 2 0 1 0 0 2 2 1 3 7 1 4 3 1 5 6 2 6 5 2 7 7 2 8 1 3 9 7 3 10 5 3 11 0 4 12 3 4 13 1 4 14 4 5 15 1 5 16 5 5 17 4 0 18 6 0 19 2 0 20 2 1 21 6 1 22 7 1 23 6 2 24 4 2 25 5 2 26 1 3 27 3 3 28 7 3 29 0 4 30 2 4 31 3 4 32 4 5 33 0 5 34 1 5 35 + + + + + + + + 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demos/3d/simple/cube.scn b/demos/3d/simple/cube.scn new file mode 100644 index 00000000..d28d5903 Binary files /dev/null and b/demos/3d/simple/cube.scn differ diff --git a/demos/3d/simple/engine.cfg b/demos/3d/simple/engine.cfg new file mode 100644 index 00000000..72ee4aa6 --- /dev/null +++ b/demos/3d/simple/engine.cfg @@ -0,0 +1,5 @@ +[application] + +name="simple" +main_scene="res://main.scn" +icon="icon.png" diff --git a/demos/3d/simple/icon.png b/demos/3d/simple/icon.png new file mode 100644 index 00000000..0c422e37 Binary files /dev/null and b/demos/3d/simple/icon.png differ diff --git a/demos/3d/simple/icon.png.flags b/demos/3d/simple/icon.png.flags new file mode 100644 index 00000000..dbef2209 --- /dev/null +++ b/demos/3d/simple/icon.png.flags @@ -0,0 +1 @@ +gen_mipmaps=true diff --git a/demos/3d/simple/main.scn b/demos/3d/simple/main.scn new file mode 100644 index 00000000..7d1f1305 Binary files /dev/null and b/demos/3d/simple/main.scn differ diff --git a/demos/misc/simple_audio/.fscache b/demos/misc/simple_audio/.fscache new file mode 100644 index 00000000..e8de5dcf --- /dev/null +++ b/demos/misc/simple_audio/.fscache @@ -0,0 +1,4 @@ +::res://::1708967223 +icon.png::ImageTexture::1708966717:: +k_jose_-_its_time.ogg::AudioStreamOGGVorbis::1708967006:: +main.scn::PackedScene::1708967223:: diff --git a/demos/misc/simple_audio/engine.cfg b/demos/misc/simple_audio/engine.cfg new file mode 100644 index 00000000..23c8a3d0 --- /dev/null +++ b/demos/misc/simple_audio/engine.cfg @@ -0,0 +1,5 @@ +[application] + +name="simple_audio" +main_scene="res://main.scn" +icon="icon.png" diff --git a/demos/misc/simple_audio/icon.png b/demos/misc/simple_audio/icon.png new file mode 100644 index 00000000..0c422e37 Binary files /dev/null and b/demos/misc/simple_audio/icon.png differ diff --git a/demos/misc/simple_audio/icon.png.flags b/demos/misc/simple_audio/icon.png.flags new file mode 100644 index 00000000..dbef2209 --- /dev/null +++ b/demos/misc/simple_audio/icon.png.flags @@ -0,0 +1 @@ +gen_mipmaps=true diff --git a/demos/misc/simple_audio/k_jose_-_its_time.ogg b/demos/misc/simple_audio/k_jose_-_its_time.ogg new file mode 100644 index 00000000..47815616 Binary files /dev/null and b/demos/misc/simple_audio/k_jose_-_its_time.ogg differ diff --git a/demos/misc/simple_audio/k_jose_-_its_time.spx b/demos/misc/simple_audio/k_jose_-_its_time.spx new file mode 100644 index 00000000..21f049bd Binary files /dev/null and b/demos/misc/simple_audio/k_jose_-_its_time.spx differ diff --git a/demos/misc/simple_audio/main.scn b/demos/misc/simple_audio/main.scn new file mode 100644 index 00000000..a96e7b6d Binary files /dev/null and b/demos/misc/simple_audio/main.scn differ diff --git a/drivers/SCsub b/drivers/SCsub index 40af5fc3..99d2ddd4 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -8,11 +8,13 @@ Export('env') SConscript('unix/SCsub'); SConscript('alsa/SCsub'); SConscript('windows/SCsub'); -if env["platform"] in ("x11", "vita"): + +if env["platform"] in ("x11", "vita", "javascript"): SConscript('gles2/SCsub'); if env["platform"] in ("x11soft", "windows"): SConscript('gl11/SCsub'); -elif env["platform"] != "vita": +else: + SConscript('gles1/SCsub'); SConscript('gl_context/SCsub'); SConscript('openssl/SCsub'); diff --git a/drivers/gles1/rasterizer_gles1.cpp b/drivers/gles1/rasterizer_gles1.cpp index f3e8c201..b4ccb9d3 100644 --- a/drivers/gles1/rasterizer_gles1.cpp +++ b/drivers/gles1/rasterizer_gles1.cpp @@ -26,7 +26,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef GLES1_ENABLED +#if defined(GLES1_ENABLED) || defined(__psp2__) #include "rasterizer_gles1.h" #include "os/os.h" @@ -38,6 +38,27 @@ #include "gl_context/context_gl.h" #include +#ifndef GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT +#define GL_TEXTURE_CUBE_MAP_OES GL_TEXTURE_CUBE_MAP_EXT +#endif + +#ifdef __psp2__ +#include +#include +#endif + +#ifndef GL_TEXTURE_GEN_MODE_OES +#define GL_TEXTURE_GEN_MODE_OES GL_TEXTURE_GEN_MODE +#define GL_REFLECTION_MAP_OES GL_REFLECTION_MAP_ARB +#define glTexGeniOES glTexGeni +#endif + _FORCE_INLINE_ static void _gl_load_transform(const Transform& tr) { GLfloat matrix[16]={ /* build a 16x16 matrix */ @@ -2201,45 +2222,126 @@ RID RasterizerGLES1::immediate_create() { void RasterizerGLES1::immediate_begin(RID p_immediate, VS::PrimitiveType p_rimitive, RID p_texture){ + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(im->building); + + Immediate::Chunk ic; + ic.texture=p_texture; + ic.primitive=p_rimitive; + im->chunks.push_back(ic); + im->mask=0; + im->building=true; + } void RasterizerGLES1::immediate_vertex(RID p_immediate,const Vector3& p_vertex){ + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + Immediate::Chunk *c = &im->chunks.back()->get(); + + + if (c->vertices.empty() && im->chunks.size()==1) { + + im->aabb.pos=p_vertex; + im->aabb.size=Vector3(); + } else { + im->aabb.expand_to(p_vertex); + } + + if (im->mask&VS::ARRAY_FORMAT_NORMAL) + c->normals.push_back(chunk_normal); + if (im->mask&VS::ARRAY_FORMAT_TANGENT) + c->tangents.push_back(chunk_tangent); + if (im->mask&VS::ARRAY_FORMAT_COLOR) + c->colors.push_back(chunk_color); + if (im->mask&VS::ARRAY_FORMAT_TEX_UV) + c->uvs.push_back(chunk_uv); + if (im->mask&VS::ARRAY_FORMAT_TEX_UV2) + c->uvs2.push_back(chunk_uv2); + im->mask|=VS::ARRAY_FORMAT_VERTEX; + c->vertices.push_back(p_vertex); } + + void RasterizerGLES1::immediate_normal(RID p_immediate,const Vector3& p_normal){ + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask|=VS::ARRAY_FORMAT_NORMAL; + chunk_normal=p_normal; } void RasterizerGLES1::immediate_tangent(RID p_immediate,const Plane& p_tangent){ + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask|=VS::ARRAY_FORMAT_TANGENT; + chunk_tangent=p_tangent; } void RasterizerGLES1::immediate_color(RID p_immediate,const Color& p_color){ + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask|=VS::ARRAY_FORMAT_COLOR; + chunk_color=p_color; } void RasterizerGLES1::immediate_uv(RID p_immediate,const Vector2& tex_uv){ + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask|=VS::ARRAY_FORMAT_TEX_UV; + chunk_uv=tex_uv; } void RasterizerGLES1::immediate_uv2(RID p_immediate,const Vector2& tex_uv){ + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask|=VS::ARRAY_FORMAT_TEX_UV2; + chunk_uv2=tex_uv; } void RasterizerGLES1::immediate_end(RID p_immediate){ + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->building=false; } void RasterizerGLES1::immediate_clear(RID p_immediate) { + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(im->building); + im->chunks.clear(); } AABB RasterizerGLES1::immediate_get_aabb(RID p_immediate) const { - return AABB(Vector3(-1,-1,-1),Vector3(2,2,2)); + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND_V(!im,AABB()); + return im->aabb; } void RasterizerGLES1::immediate_set_material(RID p_immediate,RID p_material) { @@ -2247,6 +2349,7 @@ void RasterizerGLES1::immediate_set_material(RID p_immediate,RID p_material) { Immediate *im = immediate_owner.get(p_immediate); ERR_FAIL_COND(!im); im->material=p_material; + } RID RasterizerGLES1::immediate_get_material(RID p_immediate) const { @@ -2933,21 +3036,80 @@ RID RasterizerGLES1::viewport_data_create() { RID RasterizerGLES1::render_target_create(){ - return RID(); + RenderTarget *rt = memnew( RenderTarget ); + rt->fbo=0; + rt->width=0; + rt->height=0; + rt->last_pass=0; + rt->color = 0; // Add color texture to rt to use for blitting + Texture *texture = memnew(Texture); + texture->active=false; + texture->total_data_size=0; + texture->render_target=rt; + // texture->ignore_mipmaps=true; + rt->texture_ptr=texture; + rt->texture=texture_owner.make_rid( texture ); + rt->texture_ptr->active=false; + return render_target_owner.make_rid(rt); } -void RasterizerGLES1::render_target_set_size(RID p_render_target, int p_width, int p_height){ + +void RasterizerGLES1::render_target_set_size(RID p_render_target,int p_width,int p_height){ + + RenderTarget *rt = render_target_owner.get(p_render_target); + + if (p_width==rt->width && p_height==rt->height) + return; + + if (rt->width!=0 && rt->height!=0) { + + glDeleteTextures(1,&rt->color); + + rt->width=0; + rt->height=0; + rt->texture_ptr->tex_id=0; + rt->texture_ptr->active=false; + + } + + if (p_width==0 || p_height==0) + return; + + + rt->width=p_width; + rt->height=p_height; + + + //color texture + glGenTextures(1, &rt->color); + glBindTexture(GL_TEXTURE_2D, rt->color); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + + rt->texture_ptr->tex_id=rt->color; + rt->texture_ptr->active=true; + rt->texture_ptr->width=p_width; + rt->texture_ptr->height=p_height; } -RID RasterizerGLES1::render_target_get_texture(RID p_render_target) const{ - return RID(); +RID RasterizerGLES1::render_target_get_texture(RID p_render_target) const{ + const RenderTarget *rt = render_target_owner.get(p_render_target); + ERR_FAIL_COND_V(!rt,RID()); + return rt->texture; } + bool RasterizerGLES1::render_target_renedered_in_frame(RID p_render_target){ - return false; + RenderTarget *rt = render_target_owner.get(p_render_target); + ERR_FAIL_COND_V(!rt,false); + return rt->last_pass==frame; } @@ -2978,8 +3140,32 @@ void RasterizerGLES1::begin_frame() { } void RasterizerGLES1::capture_viewport(Image* r_capture) { + DVector pixels; + pixels.resize(viewport.width * viewport.height * 4); + DVector::Write w = pixels.write(); + glPixelStorei(GL_PACK_ALIGNMENT, 4); + glReadPixels(viewport.x, window_size.height - (viewport.height + viewport.y), viewport.width, viewport.height, GL_RGBA, GL_UNSIGNED_BYTE, w.ptr()); + + bool flip = true;//current_rt == NULL; + + if (flip) { + uint32_t *imgptr = (uint32_t *)w.ptr(); + for (int y = 0; y < (viewport.height / 2); y++) { + uint32_t *ptr1 = &imgptr[y * viewport.width]; + uint32_t *ptr2 = &imgptr[(viewport.height - y - 1) * viewport.width]; + for (int x = 0; x < viewport.width; x++) { + + uint32_t tmp = ptr1[x]; + ptr1[x] = ptr2[x]; + ptr2[x] = tmp; + } + } + } + + w = DVector::Write(); + r_capture->create(viewport.width, viewport.height, 0, Image::FORMAT_RGBA, pixels); } @@ -3260,6 +3446,13 @@ void RasterizerGLES1::add_multimesh( const RID& p_multimesh, const InstanceData } +void RasterizerGLES1::add_immediate(const RID &p_immediate, const InstanceData *p_data) { + + Immediate *immediate = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!immediate); + + _add_geometry(immediate, p_data, immediate, NULL); +} void RasterizerGLES1::add_particles( const RID& p_particle_instance, const InstanceData *p_data){ @@ -3386,40 +3579,79 @@ void RasterizerGLES1::_setup_fixed_material(const Geometry *p_geometry,const Mat } - +#ifndef __psp2__ if(p_material->fixed_flags[VS::FIXED_MATERIAL_FLAG_USE_ENVMAP] && p_material->textures[VS::FIXED_MATERIAL_PARAM_ENVMAP].is_valid()) { Texture *texture = texture_owner.get( p_material->textures[VS::FIXED_MATERIAL_PARAM_ENVMAP] ); ERR_FAIL_COND(!texture); - glEnable(GL_TEXTURE_2D); - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + glActiveTexture(GL_TEXTURE0); + glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); - glActiveTexture(GL_TEXTURE0); + + + glTexGeniOES(GL_S, GL_TEXTURE_GEN_MODE_OES, GL_REFLECTION_MAP_OES); + glTexGeniOES(GL_T, GL_TEXTURE_GEN_MODE_OES, GL_REFLECTION_MAP_OES); + glTexGeniOES(GL_R, GL_TEXTURE_GEN_MODE_OES, GL_REFLECTION_MAP_OES); + glBindTexture( GL_TEXTURE_2D,texture->tex_id ); // glDisable(GL_TEXTURE_GEN_S); // glDisable(GL_TEXTURE_GEN_T); + } else { + // glDisable(GL_TEXTURE_CUBE_MAP_OES); + glActiveTexture(GL_TEXTURE0); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); + glDisable(GL_TEXTURE_GEN_R); + glDisable(GL_TEXTURE_2D); + +#else + + if(p_material->fixed_flags[VS::FIXED_MATERIAL_FLAG_USE_ENVMAP] && p_material->textures[VS::FIXED_MATERIAL_PARAM_ENVMAP].is_valid()) { + + Texture *texture = texture_owner.get( p_material->textures[VS::FIXED_MATERIAL_PARAM_ENVMAP] ); + ERR_FAIL_COND(!texture); + + glActiveTexture(GL_TEXTURE0); + glEnable(GL_TEXTURE_2D); + glEnable(GL_TEXTURE_GEN_STR_OES); + + glTexGeniOES(GL_TEXTURE_GEN_STR_OES, GL_TEXTURE_GEN_MODE_OES, GL_REFLECTION_MAP_OES); + glBindTexture( GL_TEXTURE_2D,texture->tex_id ); + + } else { + glActiveTexture(GL_TEXTURE0); + glDisable(GL_TEXTURE_GEN_STR_OES); glDisable(GL_TEXTURE_2D); +#endif if (p_material->textures[VS::FIXED_MATERIAL_PARAM_DIFFUSE].is_valid()) { Texture *texture = texture_owner.get( p_material->textures[VS::FIXED_MATERIAL_PARAM_DIFFUSE] ); ERR_FAIL_COND(!texture); - glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + glEnable(GL_TEXTURE_2D); glBindTexture( GL_TEXTURE_2D,texture->tex_id ); + + // tc0_id_cache = texture->tex_id; + } else if(p_material->fixed_flags[VS::FIXED_MATERIAL_FLAG_USE_REFLECTION]) { + glActiveTexture(GL_TEXTURE0); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, reflect_texture); + reflect = true; } else { - + // glDisable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); glDisable(GL_TEXTURE_2D); + } +// #ifndef __psp2__ } - +// #endif } @@ -3729,6 +3961,23 @@ static const int gl_texcoord_index[VS::ARRAY_MAX-1] = { -1, // ARRAY_WEIGHTS }; +static const GLenum gl_primitive[]={ + GL_POINTS, + GL_LINES, + GL_LINE_STRIP, + GL_LINE_LOOP, + GL_TRIANGLES, + GL_TRIANGLE_STRIP, + GL_TRIANGLE_FAN +}; + +static const GLenum gl_poly_primitive[4]={ + GL_POINTS, + GL_LINES, + GL_TRIANGLES, + //GL_QUADS + +}; Error RasterizerGLES1::_setup_geometry(const Geometry *p_geometry, const Material* p_material, const Skeleton *p_skeleton,const float *p_morphs) { @@ -4014,7 +4263,7 @@ Error RasterizerGLES1::_setup_geometry(const Geometry *p_geometry, const Materia } if (gl_texcoord_index[i] != -1) { - glClientActiveTexture(GL_TEXTURE0+gl_texcoord_index[i]); + glClientActiveTexture(GL_TEXTURE0+client_tex_index); } glEnableClientState(gl_client_states[i]); @@ -4058,7 +4307,98 @@ Error RasterizerGLES1::_setup_geometry(const Geometry *p_geometry, const Materia } break; + case Geometry::GEOMETRY_IMMEDIATE: { + bool restore_tex=false; + const Immediate *im = static_cast( p_geometry ); + if (im->building) { + break; + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glClientActiveTexture(GL_TEXTURE0); + + for (const List::Element *E = im->chunks.front(); E; E = E->next()) { + + const Immediate::Chunk &c = E->get(); + if (c.vertices.empty()) { + continue; + } + + // what on earth? + //for (int i = 0; i < c.vertices.size(); i++) + + if (c.texture.is_valid() && texture_owner.owns(c.texture)) { + + const Texture *t = texture_owner.get(c.texture); + // Texture2D should always be enabled + glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0 + tc0_idx); + glBindTexture(t->target, t->tex_id); + restore_tex = true; + + } + else if (restore_tex) { + + glActiveTexture(GL_TEXTURE0 + tc0_idx); + glBindTexture(GL_TEXTURE_2D, tc0_id_cache); + restore_tex = false; + } + + if (!c.normals.empty()) { + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, c.normals.ptr()); + } + else { + glDisableClientState(GL_NORMAL_ARRAY); + } + + if (!c.colors.empty()) { + + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(4, GL_FLOAT, 0, c.colors.ptr()); + } + else { + + glDisableClientState(GL_COLOR_ARRAY); + glColor4f(1, 1, 1, 1); + } + + if (!c.uvs.empty()) { + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 0, c.uvs.ptr()); + } + else { + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, c.vertices.ptr()); + glDrawArrays(gl_primitive[c.primitive], 0, c.vertices.size()); + } + + if (restore_tex) { + glActiveTexture(GL_TEXTURE0 + tc0_idx); + glBindTexture(GL_TEXTURE_2D, tc0_id_cache); + restore_tex = false; + } + + // reset the client states just in case cus the driver explodes if I don't + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + // if (restore_tex) { + // + // glActiveTexture(GL_TEXTURE0+tc0_idx); + // glBindTexture(GL_TEXTURE_2D,tc0_id_cache); + // restore_tex=false; + // } + glDisable(GL_TEXTURE_2D); + } break; default: break; }; @@ -4066,23 +4406,7 @@ Error RasterizerGLES1::_setup_geometry(const Geometry *p_geometry, const Materia return OK; }; -static const GLenum gl_primitive[]={ - GL_POINTS, - GL_LINES, - GL_LINE_STRIP, - GL_LINE_LOOP, - GL_TRIANGLES, - GL_TRIANGLE_STRIP, - GL_TRIANGLE_FAN -}; -static const GLenum gl_poly_primitive[4]={ - GL_POINTS, - GL_LINES, - GL_TRIANGLES, - //GL_QUADS - -}; void RasterizerGLES1::_render(const Geometry *p_geometry,const Material *p_material, const Skeleton* p_skeleton, const GeometryOwner *p_owner) { @@ -4357,20 +4681,22 @@ void RasterizerGLES1::_render_list_forward(RenderList *p_render_list,bool p_reve bool bind_baked_light_octree=false; bool bind_baked_lightmap=false; + bool normal_map = false; if (e->instance->sampled_light.is_valid()) { SampledLight *sl = sampled_light_owner.get(e->instance->sampled_light); if (sl) { - // baked_light=NULL; //can't mix + baked_light=NULL; //can't mix // material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_DP_SAMPLER,true); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,sl->texture); //bind the texture } } if (baked_light) { - if (baked_light->mode==VS::BAKED_LIGHT_OCTREE && baked_light->octree_texture.is_valid() && e->instance->baked_light_octree_xform) { + // glEnable(GL_TEXTURE_2D); + /*if (baked_light->mode==VS::BAKED_LIGHT_OCTREE && baked_light->octree_texture.is_valid() && e->instance->baked_light_octree_xform) { // material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE,true); bind_baked_light_octree=true; if (prev_baked_light!=baked_light) { @@ -4391,9 +4717,9 @@ void RasterizerGLES1::_render_list_forward(RenderList *p_render_list,bool p_reve } - } else if (baked_light->mode==VS::BAKED_LIGHT_LIGHTMAPS) { - + } else*/ if (baked_light->mode==VS::BAKED_LIGHT_LIGHTMAPS) { + int lightmap_idx = e->instance->baked_lightmap_id; // material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,false); @@ -4410,10 +4736,11 @@ void RasterizerGLES1::_render_list_forward(RenderList *p_render_list,bool p_reve Texture *tex = texture_owner.get(texid); if (tex) { - - glActiveTexture(GL_TEXTURE0); - glBindTexture(tex->target,tex->tex_id); //bind the texture - } + // glEnable(GL_TEXTURE_2D); + // glActiveTexture(GL_TEXTURE1); + // glBindTexture(tex->target,tex->tex_id); //bind the texture + // glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } prev_baked_light_texture=texid; } @@ -4424,10 +4751,35 @@ void RasterizerGLES1::_render_list_forward(RenderList *p_render_list,bool p_reve } } + } else { + + // glDisable(GL_TEXTURE_2D); } + + if(!normal_map) { + + glActiveTexture(GL_TEXTURE1); + glClientActiveTexture(GL_TEXTURE1); + glDisable(GL_TEXTURE_2D); + } if (material!=prev_material || geometry_cmp!=prev_geometry_cmp) { _setup_material(e->geometry,material); + if(material->textures[VS::FIXED_MATERIAL_PARAM_NORMAL].is_valid() && material->textures[VS::FIXED_MATERIAL_PARAM_DIFFUSE].is_valid()) { + normal_map = true; + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + } + /* + if(bind_baked_lightmap) { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + + }*/ _rinfo.mat_change_count++; //_setup_material_overrides(e->material,NULL,material_overrides); //_setup_material_skeleton(material,skeleton); @@ -4438,12 +4790,28 @@ void RasterizerGLES1::_render_list_forward(RenderList *p_render_list,bool p_reve }; } - + client_tex_index = 0; if (geometry_cmp!=prev_geometry_cmp || prev_skeleton!=skeleton) { _setup_geometry(e->geometry, material,e->skeleton,e->instance->morph_values.ptr()); }; + if(normal_map) { + Texture *normal = texture_owner.get( material->textures[VS::FIXED_MATERIAL_PARAM_NORMAL] ); + ERR_FAIL_COND(!normal); + + + + glActiveTexture(GL_TEXTURE1); + + glClientActiveTexture(GL_TEXTURE1); + glEnable(GL_TEXTURE_2D); + // _render(e->geometry, material, skeleton,e->owner); + client_tex_index = 1; + _setup_geometry(e->geometry, material,e->skeleton,e->instance->morph_values.ptr()); + glBindTexture( GL_TEXTURE_2D,normal->tex_id ); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + } // if (i==0 || light_key!=prev_light_key) { // printf("setup\n"); _setup_lights(e->lights,e->light_count); //dunno how inefficent is but it fixes lights @@ -4492,11 +4860,11 @@ void RasterizerGLES1::_render_list_forward(RenderList *p_render_list,bool p_reve //bool changed_shader = material_shader.bind(); //if ( changed_shader && material->shader_cache && !material->shader_cache->params.empty()) // _setup_shader_params(material); - _render(e->geometry, material, skeleton,e->owner); + prev_material=material; prev_skeleton=skeleton; // prev_geometry=geometry; @@ -4511,7 +4879,7 @@ void RasterizerGLES1::_render_list_forward(RenderList *p_render_list,bool p_reve }; void RasterizerGLES1::_process_blur(int times, float inc) { - +#ifndef __psp2__ float spost = 0.0f; float alphainc = 0.9f / times; float alpha = 0.2f; @@ -4619,6 +4987,7 @@ void RasterizerGLES1::_process_blur(int times, float inc) { glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); +#endif } @@ -4798,8 +5167,16 @@ void RasterizerGLES1::end_scene() { // material_shader.set_conditional( MaterialShaderGLES1::USE_FOG,false); if(current_env->fx_enabled[VS::ENV_FX_ES1_BLUR] && !is_editor) _process_blur(current_env->fx_param[VS::ENV_FX_PARAM_ES1_BLUR_TIMES], current_env->fx_param[VS::ENV_FX_PARAM_ES1_BLUR_ALPHA]); - - + if(!is_editor && reflect) { + // glEnable(GL_TEXTURE_CUBE_MAP_OES); + glViewport(0,0,256,256); + glBindTexture(GL_TEXTURE_2D, reflect_texture); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, 256, 256, 0); + glBindTexture(GL_TEXTURE_2D, 0); + glViewport( viewport.x, window_size.height-(viewport.height+viewport.y), viewport.width,viewport.height ); + + } + reflect = false; // _debug_shadows(); } @@ -5058,6 +5435,7 @@ void RasterizerGLES1::end_frame() { */ //print_line("VTX: "+itos(_rinfo.vertex_count)+" OBJ: "+itos(_rinfo.object_count)+" MAT: "+itos(_rinfo.mat_change_count)+" SHD: "+itos(_rinfo.shader_change_count)); + OS::get_singleton()->swap_buffers(); } @@ -6276,13 +6654,20 @@ void RasterizerGLES1::init() { glewInit(); #endif - +#ifdef __psp2__ + glTexGeniOES = (PFNGLTEXGENIOESPROC)eglGetProcAddress("glTexGeniOES"); + + if (!glTexGeniOES) { + printf("Failed to load glTexGeniOES\n"); + } +#endif scene_pass=1; +#ifndef __psp2__ if (ContextGL::get_singleton()) ContextGL::get_singleton()->make_current(); - +#endif Set extensions; @@ -6342,17 +6727,55 @@ void RasterizerGLES1::init() { s3tc_supported=false; _rinfo.texture_mem=0; - unsigned int* data; - - data = (GLuint *)calloc( 1, ((256 * 256)* 4 * sizeof(GLuint)) ); glGenTextures(1, &BlurTexture); glBindTexture(GL_TEXTURE_2D, BlurTexture); glTexImage2D(GL_TEXTURE_2D, 0, 4, 256, 256, 0, - GL_RGBA, GL_UNSIGNED_BYTE, data); + GL_LUMINANCE, GL_UNSIGNED_BYTE, 0); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); - // free(data); TODO + + glGenTextures(1, &reflect_texture); + glBindTexture(GL_TEXTURE_2D, reflect_texture); +/* + + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES, 0, 4, 256, 256, 0, + GL_RGB, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES, 0, 4, 256, 256, 0, + GL_RGB, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES, 0, 4, 256, 256, 0, + GL_RGB, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES, 0, 4, 256, 256, 0, + GL_RGB, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES, 0, 4, 256, 256, 0, + GL_RGB, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES, 0, 4, 256, 256, 0, + GL_RGB, GL_UNSIGNED_BYTE, 0);*/ + + +#ifdef __psp2__ + glEnable(GL_TEXTURE_GEN_STR_OES); + glTexGeniOES(GL_TEXTURE_GEN_STR_OES, GL_TEXTURE_GEN_MODE_OES, GL_REFLECTION_MAP_OES); +#else + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + glEnable(GL_TEXTURE_GEN_R); + glTexGeniOES(GL_S, GL_TEXTURE_GEN_MODE_OES, GL_REFLECTION_MAP_OES); + glTexGeniOES(GL_T, GL_TEXTURE_GEN_MODE_OES, GL_REFLECTION_MAP_OES); + glTexGeniOES(GL_R, GL_TEXTURE_GEN_MODE_OES, GL_REFLECTION_MAP_OES); + +#endif + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +#ifdef __psp2__ + glDisable(GL_TEXTURE_GEN_STR_OES); +#else + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + glDisable(GL_TEXTURE_GEN_R); +#endif } void RasterizerGLES1::finish() { diff --git a/drivers/gles1/rasterizer_gles1.h b/drivers/gles1/rasterizer_gles1.h index eb5e9efd..b3bcd338 100644 --- a/drivers/gles1/rasterizer_gles1.h +++ b/drivers/gles1/rasterizer_gles1.h @@ -31,7 +31,7 @@ #include "servers/visual/rasterizer.h" -#ifdef GLES1_ENABLED +#if defined(GLES1_ENABLED) || defined(__psp2__) #include "image.h" #include "rid.h" @@ -62,14 +62,25 @@ class RasterizerGLES1 : public Rasterizer { MAX_SCENE_LIGHTS=2048, LIGHT_SPOT_BIT=0x80, DEFAULT_SKINNED_BUFFER_SIZE = 1024 * 1024, // 10k vertices +#ifdef __psp2__ + MAX_HW_LIGHTS = 8, //Yay! 8 Lights :blush: +#else MAX_HW_LIGHTS = 4, +#endif }; + +#ifdef __psp2__ + typedef void (*PFNGLTEXGENIOESPROC)(GLenum coord, GLenum pname, GLint param); + PFNGLTEXGENIOESPROC glTexGeniOES = NULL; +#endif + #ifdef PSP void glActiveTexture(int a1) { }; void glClientActiveTexture(int a1) { }; #endif GLuint BlurTexture; + GLuint reflect_texture; uint8_t *skinned_buffer; int skinned_buffer_size; @@ -80,10 +91,13 @@ class RasterizerGLES1 : public Rasterizer { bool pack_arrays; bool use_reload_hooks; bool is_editor; - + uint8_t client_tex_index = 0; + bool reflect = false; Image _get_gl_image_and_format(const Image& p_image, Image::Format p_format, uint32_t p_flags,GLenum& r_gl_format,int &r_gl_components,bool &r_has_alpha_cache,bool &r_compressed); + + class RenderTarget; struct Texture { @@ -100,6 +114,7 @@ class RasterizerGLES1 : public Rasterizer { bool compressed; bool disallow_mipmaps; int total_data_size; + RenderTarget *render_target; Image image[6]; @@ -110,7 +125,7 @@ class RasterizerGLES1 : public Rasterizer { StringName reloader_func; Texture() { - + render_target = NULL; flags=width=height=0; tex_id=0; data_size=0; @@ -213,6 +228,7 @@ class RasterizerGLES1 : public Rasterizer { enum Type { GEOMETRY_INVALID, GEOMETRY_SURFACE, + GEOMETRY_IMMEDIATE, GEOMETRY_POLY, GEOMETRY_PARTICLES, GEOMETRY_MULTISURFACE, @@ -409,10 +425,27 @@ class RasterizerGLES1 : public Rasterizer { mutable RID_Owner multimesh_owner; mutable SelfList::List _multimesh_dirty_list; - struct Immediate { + struct Immediate : public Geometry { + + struct Chunk { + + RID texture; + VS::PrimitiveType primitive; + Vector vertices; + Vector normals; + Vector tangents; + Vector colors; + Vector uvs; + Vector uvs2; + }; + + List chunks; + bool building; + int mask; + AABB aabb; + + Immediate() { type=GEOMETRY_IMMEDIATE; building=false;} - RID material; - int empty; }; mutable RID_Owner immediate_owner; @@ -451,6 +484,21 @@ class RasterizerGLES1 : public Rasterizer { mutable RID_Owner skeleton_owner; + + struct RenderTarget { + + Texture *texture_ptr; + RID texture; + GLuint fbo; + GLuint color; + GLuint depth; + int width,height; + uint64_t last_pass; + + }; + + mutable RID_Owner render_target_owner; + struct Light { VS::LightType type; @@ -716,7 +764,8 @@ class RasterizerGLES1 : public Rasterizer { RenderList opaque_render_list; RenderList alpha_render_list; - + // RenderList reflection_render_list; + RID default_material; struct FX { @@ -796,7 +845,14 @@ class RasterizerGLES1 : public Rasterizer { Error _setup_geometry(const Geometry *p_geometry, const Material* p_material,const Skeleton *p_skeleton, const float *p_morphs); void _render(const Geometry *p_geometry,const Material *p_material, const Skeleton* p_skeleton, const GeometryOwner *p_owner); - + Vector3 chunk_vertex; + Vector3 chunk_normal; + Plane chunk_tangent; + Color chunk_color; + Vector2 chunk_uv; + Vector2 chunk_uv2; + GLuint tc0_id_cache; + GLuint tc0_idx = 0; /***********/ /* SHADOWS */ @@ -1192,7 +1248,7 @@ class RasterizerGLES1 : public Rasterizer { virtual void add_mesh( const RID& p_mesh, const InstanceData *p_data); virtual void add_multimesh( const RID& p_multimesh, const InstanceData *p_data); - virtual void add_immediate( const RID& p_immediate, const InstanceData *p_data) {} + virtual void add_immediate( const RID& p_immediate, const InstanceData *p_data); virtual void add_particles( const RID& p_particle_instance, const InstanceData *p_data); virtual void end_scene(); diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index 50b63e1a..ed636da5 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -488,10 +488,10 @@ Error ShaderCompilerGLES2::compile_node(SL::ProgramNode *p_program) { header+=_typestr(fnode->arguments[i].type)+" "+replace_string(fnode->arguments[i].name); } - header+=") {"ENDL; + header+=") {" ENDL; String fcode=header; fcode+=dump_node_code(fnode->body,1); - fcode+="}"ENDL; + fcode+="}" ENDL; global_code+=fcode; } diff --git a/drivers/mpc/mpc_reader.c b/drivers/mpc/mpc_reader.c index e1d151fe..05197751 100644 --- a/drivers/mpc/mpc_reader.c +++ b/drivers/mpc/mpc_reader.c @@ -36,6 +36,7 @@ #include #include "internal.h" #include +#include #define STDIO_MAGIC 0xF34B963C ///< Just a random safe-check value... typedef struct mpc_reader_stdio_t { diff --git a/drivers/theoraplayer/SCsub b/drivers/theoraplayer/SCsub index cd8cabcc..dd349af1 100644 --- a/drivers/theoraplayer/SCsub +++ b/drivers/theoraplayer/SCsub @@ -2,7 +2,7 @@ Import("env") import string -sources = string.split(""" +sources = """ src/TheoraVideoClip.cpp src/FFmpeg/TheoraVideoClip_FFmpeg.cpp src/TheoraAsync.cpp @@ -59,7 +59,7 @@ src/YUV/C/yuv420_grey_c.c src/YUV/C/yuv420_yuv_c.c src/YUV/C/yuv420_rgb_c.c src/TheoraVideoFrame.cpp -""") +""".split() if env["platform"] == "iphone": sources.append("src/AVFoundation/TheoraVideoClip_AVFoundation.mm") diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index e84a1790..58173035 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -28,9 +28,11 @@ /*************************************************************************/ #include "dir_access_unix.h" -#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) || defined(PSP) || defined(__psp2__) -#if !defined(PSP) && !defined(__psp2__) && !defined(DREAMCAST) +#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) || defined(PSP) || defined(__psp2__) || defined(__3DS__) + +#if !defined(PSP) && !defined(__psp2__) && !defined(DREAMCAST) && !defined(__3DS__) + #include #endif @@ -300,7 +302,8 @@ Error DirAccessUnix::remove(String p_path) { size_t DirAccessUnix::get_space_left() { -#if !defined(PSP) && !defined(__psp2__) && !defined(DREAMCAST) + +#if !defined(PSP) && !defined(__psp2__) && !defined(DREAMCAST) && !defined(__3DS__) struct statvfs vfs; if (statvfs(current_dir.utf8().get_data(), &vfs) != 0) { diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h index c6d98191..350ec446 100644 --- a/drivers/unix/dir_access_unix.h +++ b/drivers/unix/dir_access_unix.h @@ -29,7 +29,8 @@ #ifndef DIR_ACCESS_UNIX_H #define DIR_ACCESS_UNIX_H -#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) || defined(PSP) || defined(__psp2__) +#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) || defined(PSP) || defined(__3DS__) || defined(__psp2__) + #include #include diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index 5b4ec897..05f67f53 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -28,14 +28,15 @@ /*************************************************************************/ #include "file_access_unix.h" -#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) || defined(PSP) || defined(__psp2__) +#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) || defined(PSP) || defined(__psp2__) || defined(__3DS__) #include #include #include "print_string.h" #include "core/os/os.h" -#if !defined(PSP) && !defined(__psp2__) && !defined(DREAMCAST) +#if !defined(PSP) && !defined(__psp2__) && !defined(DREAMCAST) && !defined(__3DS__) + #include #endif diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index 8de993f3..1ce68aa5 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -33,7 +33,8 @@ #include "os/memory.h" #include -#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) || defined(PSP) || defined(__psp2__) +#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) || defined(PSP) || defined(__psp2__) || defined(__3DS__) + /** @author Juan Linietsky diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index a91b5f2d..d8a3f9f3 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.cpp @@ -28,7 +28,9 @@ /*************************************************************************/ #include "ip_unix.h" -#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED) && !defined(WINRT_ENABLED) || defined(PSP) + +#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED) && !defined(WINRT_ENABLED) || defined(__3DS__) || defined(PSP) + #ifdef WINDOWS_ENABLED @@ -47,7 +49,7 @@ #endif #else #include -#ifndef PSP +#if !defined(__3DS__) && !defined(PSP) #ifdef ANDROID_ENABLED #include "platform/android/ifaddrs_android.h" #else @@ -74,12 +76,15 @@ IP_Address IP_Unix::_resolve_hostname(const String& p_hostname) { } -#if defined(PSP) + +#if defined(PSP) || defined(__3DS__) + void IP_Unix::get_local_addresses(List *r_addresses) const { }; -#else + +#else #if defined(WINDOWS_ENABLED) @@ -146,6 +151,9 @@ void IP_Unix::get_local_addresses(List *r_addresses) const { #endif + +// #else + #else void IP_Unix::get_local_addresses(List *r_addresses) const { diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h index 9f3db553..32c557e3 100644 --- a/drivers/unix/ip_unix.h +++ b/drivers/unix/ip_unix.h @@ -31,7 +31,8 @@ #include "io/ip.h" -#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED) || defined(PSP) +#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED) || defined(__3DS__) || defined(PSP) + class IP_Unix : public IP { OBJ_TYPE(IP_Unix, IP); diff --git a/drivers/unix/packet_peer_udp_posix.cpp b/drivers/unix/packet_peer_udp_posix.cpp index 26a0b292..226f565a 100644 --- a/drivers/unix/packet_peer_udp_posix.cpp +++ b/drivers/unix/packet_peer_udp_posix.cpp @@ -117,7 +117,7 @@ Error PacketPeerUDPPosix::_poll(bool p_wait) { struct sockaddr_in from = {0}; socklen_t len = sizeof(struct sockaddr_in); int ret; - while ( (ret = recvfrom(sockfd, recv_buffer, MIN(sizeof(recv_buffer),rb.data_left()-12), p_wait?0:MSG_DONTWAIT, (struct sockaddr*)&from, &len)) > 0) { + while ( (ret = recvfrom(sockfd, recv_buffer, MIN(sizeof(recv_buffer),rb.data_left()-12), 0, (struct sockaddr*)&from, &len)) > 0) { rb.write((uint8_t*)&from.sin_addr, 4); uint32_t port = ntohs(from.sin_port); rb.write((uint8_t*)&port, 4); diff --git a/drivers/unix/semaphore_posix.cpp b/drivers/unix/semaphore_posix.cpp index 6f1b8931..0f9c8179 100644 --- a/drivers/unix/semaphore_posix.cpp +++ b/drivers/unix/semaphore_posix.cpp @@ -56,8 +56,9 @@ Error SemaphorePosix::post() { int SemaphorePosix::get() const { int val; +#ifndef JAVASCRIPT_ENABLED sem_getvalue(&sem, &val); - +#endif return val; } diff --git a/drivers/unix/stream_peer_tcp_posix.cpp b/drivers/unix/stream_peer_tcp_posix.cpp index b354f983..1c593b31 100644 --- a/drivers/unix/stream_peer_tcp_posix.cpp +++ b/drivers/unix/stream_peer_tcp_posix.cpp @@ -26,9 +26,12 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#if defined(UNIX_ENABLED) || defined(PSP) + +#if defined(UNIX_ENABLED) || defined(__3DS__) || defined(PSP) #include "stream_peer_tcp_posix.h" + #include + #ifndef PSP #include @@ -62,7 +65,7 @@ #endif static void set_addr_in(struct sockaddr_in& their_addr, const IP_Address& p_host, uint16_t p_port) { - + // printf("%s\n", p_host.host); their_addr.sin_family = AF_INET; // host byte order their_addr.sin_port = htons(p_port); // short, network byte order their_addr.sin_addr = *((struct in_addr*)&p_host.host); @@ -169,7 +172,9 @@ Error StreamPeerTCPPosix::connect(const IP_Address& p_host, uint16_t p_port) { //perror("socket"); return FAILED; }; -#ifndef PSP +#if !defined(__3DS__) && ! defined(PSP) + + #ifndef NO_FCNTL fcntl(sockfd, F_SETFL, O_NONBLOCK); #else @@ -177,6 +182,38 @@ Error StreamPeerTCPPosix::connect(const IP_Address& p_host, uint16_t p_port) { ioctl(sockfd, FIONBIO, &bval); #endif #endif + +#ifdef __3DS__ + #define atoa(x) #x + struct addrinfo hints; + struct addrinfo *resaddr = NULL, *resaddr_cur; + memset(&hints, 0, sizeof(struct addrinfo)); + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + //TODO: Do not embed this + if(getaddrinfo("google.com", "80", &hints, &resaddr)!=0) + { + printf("getaddrinfo() failed.\n"); + closesocket(sockfd); + // return; + } + + for(resaddr_cur = resaddr; resaddr_cur!=NULL; resaddr_cur = resaddr_cur->ai_next) + { + if(::connect(sockfd, resaddr_cur->ai_addr, resaddr_cur->ai_addrlen)==0)break; + } + + freeaddrinfo(resaddr); + + if(resaddr_cur==NULL) + { + printf("Failed to connect.\n"); + closesocket(sockfd); + // return; + } +#else + struct sockaddr_in their_addr; set_addr_in(their_addr, p_host, p_port); @@ -187,7 +224,7 @@ Error StreamPeerTCPPosix::connect(const IP_Address& p_host, uint16_t p_port) { disconnect(); return FAILED; }; - +#endif if (errno == EINPROGRESS) { status = STATUS_CONNECTING; } else { @@ -227,8 +264,11 @@ Error StreamPeerTCPPosix::write(const uint8_t* p_data,int p_bytes, int &r_sent, int total_sent = 0; while (data_to_send) { - +#ifdef JAVASCRIPT_ENABLED + int sent_amount = send(sockfd, offset, data_to_send, 0); +#else int sent_amount = send(sockfd, offset, data_to_send, MSG_NOSIGNAL); +#endif //printf("Sent TCP data of %d bytes, errno %d\n", sent_amount, errno); if (sent_amount == -1) { diff --git a/drivers/unix/stream_peer_tcp_posix.h b/drivers/unix/stream_peer_tcp_posix.h index 58c5dffb..b978fde5 100644 --- a/drivers/unix/stream_peer_tcp_posix.h +++ b/drivers/unix/stream_peer_tcp_posix.h @@ -26,7 +26,9 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#if defined(UNIX_ENABLED) || defined(PSP) + +#if defined(UNIX_ENABLED) || defined(PSP) || defined(__3DS__) + #ifndef STREAM_PEER_TCP_POSIX_H #define STREAM_PEER_TCP_POSIX_H diff --git a/drivers/unix/tcp_server_posix.cpp b/drivers/unix/tcp_server_posix.cpp index 76e151e3..7a9a6b6a 100644 --- a/drivers/unix/tcp_server_posix.cpp +++ b/drivers/unix/tcp_server_posix.cpp @@ -29,10 +29,14 @@ #include "tcp_server_posix.h" #include "stream_peer_tcp_posix.h" -#if defined(UNIX_ENABLED) || defined(PSP) +#if defined(UNIX_ENABLED) || defined(__3DS__) || defined(PSP) + #ifndef PSP #include + + #include + #else #include #endif diff --git a/drivers/unix/tcp_server_posix.h b/drivers/unix/tcp_server_posix.h index 0ff5aaaf..732fa690 100644 --- a/drivers/unix/tcp_server_posix.h +++ b/drivers/unix/tcp_server_posix.h @@ -29,7 +29,8 @@ #ifndef TCP_SERVER_POSIX_H #define TCP_SERVER_POSIX_H -#if defined(UNIX_ENABLED) || defined(PSP) +#if defined(UNIX_ENABLED) || defined(PSP) || defined(__3DS__) + #include "core/io/tcp_server.h" class TCPServerPosix : public TCP_Server { diff --git a/platform/3ds/SCsub b/platform/3ds/SCsub new file mode 100644 index 00000000..2fa14e07 --- /dev/null +++ b/platform/3ds/SCsub @@ -0,0 +1,16 @@ +import shlex +from SCons.Node import NodeList + +Import('env') + +SConscript("shaders/SCsub") + +common_3ds=[\ + "os_3ds.cpp",\ + "rasterizer_3ds.cpp",\ + "audio_driver_3ds.cpp",\ + "thread_3ds.cpp",\ + "thread_wrap.cpp",\ +] + +prog = env.Program('#bin/godot_3ds',['godot_3ds.cpp']+common_3ds) diff --git a/platform/3ds/audio_driver_3ds.cpp b/platform/3ds/audio_driver_3ds.cpp new file mode 100644 index 00000000..60180e54 --- /dev/null +++ b/platform/3ds/audio_driver_3ds.cpp @@ -0,0 +1,182 @@ +/*************************************************************************/ +/* audio_driver_3ds.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 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 __3DS__ +#include "audio_driver_3ds.h" +#include "thread_3ds.h" +#include "globals.h" +#include "os/os.h" +#include + +static int channel_num = 1; + + +Error AudioDriver3ds::init() { + if (ndspInit() < 0) + return FAILED; + + active=false; + thread_exited=false; + exit_thread=false; + pcm_open = false; + samples_in = NULL; + + mix_rate = 44100; + output_format = OUTPUT_STEREO; + channels = 2; + + int latency = GLOBAL_DEF("audio/output_latency",25); + buffer_size = nearest_power_of_2( latency * mix_rate / 1000 ); + + samples_in = memnew_arr(int32_t, buffer_size*channels); + + ndspWaveBuf* buffer = ndsp_buffers; + for (int i = 0; i < NDSP_BUFFER_COUNT; ++i) { + memset(buffer, 0, sizeof(ndspWaveBuf)); + buffer->data_vaddr = linearAlloc(buffer_size * channels * sizeof(int16_t)); + buffer->nsamples = buffer_size; + buffer->looping = false; + buffer->status = NDSP_WBUF_DONE; + buffer++; + } + + ndspChnReset(channel_num); + ndspChnSetInterp(channel_num, NDSP_INTERP_LINEAR); + ndspChnSetRate(channel_num, mix_rate); + ndspChnSetFormat(channel_num, (channels == 1) ? NDSP_FORMAT_MONO_PCM16 : NDSP_FORMAT_STEREO_PCM16); + + mutex = Mutex::create(); + thread = Thread3ds::create(AudioDriver3ds::thread_func, this); + + return OK; +}; + +void AudioDriver3ds::thread_func(void* p_udata) { + + int buffer_index = 0; + ndspWaveBuf* buffer; + + AudioDriver3ds* ad = (AudioDriver3ds*)p_udata; + + int sample_count = ad->buffer_size * ad->channels; + + while (!ad->exit_thread) { + + buffer = &ad->ndsp_buffers[buffer_index % NDSP_BUFFER_COUNT]; + + while (!ad->exit_thread && (!ad->active || buffer->status != NDSP_WBUF_DONE)) + OS::get_singleton()->delay_usec(10000); + + if (ad->exit_thread) + break; + + buffer->status = NDSP_WBUF_FREE; + + if (ad->active) { + ad->lock(); + ad->audio_server_process(ad->buffer_size, ad->samples_in); + ad->unlock(); + + for(int i = 0; i < sample_count; ++i) + buffer->data_pcm16[i] = ad->samples_in[i] >> 16; + + } else + memset(buffer->data_pcm16, 0, sample_count * sizeof(int16_t)); + + DSP_FlushDataCache(buffer->data_pcm16, sample_count * sizeof(int16_t)); + ndspChnWaveBufAdd(channel_num, buffer); + + buffer_index++; + } + + ndspChnWaveBufClear(channel_num); + + ad->thread_exited=true; +}; + +void AudioDriver3ds::start() { + + active = true; +}; + +int AudioDriver3ds::get_mix_rate() const { + + return mix_rate; +}; + +AudioDriverSW::OutputFormat AudioDriver3ds::get_output_format() const { + + return output_format; +}; +void AudioDriver3ds::lock() { + + if (!thread || !mutex) + return; + mutex->lock(); +}; +void AudioDriver3ds::unlock() { + + if (!thread || !mutex) + return; + mutex->unlock(); +}; + +void AudioDriver3ds::finish() { + + if (!thread) + return; + + exit_thread = true; + Thread3ds::wait_to_finish(thread); + + if (samples_in) { + memdelete_arr(samples_in); + }; + + for (int i = 0; i < NDSP_BUFFER_COUNT; ++i) + linearFree(ndsp_buffers[i].data_pcm16); + + memdelete(thread); + if (mutex) + memdelete(mutex); + thread = NULL; + + ndspExit(); +}; + +AudioDriver3ds::AudioDriver3ds() { + + mutex = NULL; + thread = NULL; +}; + +AudioDriver3ds::~AudioDriver3ds() { + +}; + +#endif diff --git a/platform/3ds/audio_driver_3ds.h b/platform/3ds/audio_driver_3ds.h new file mode 100644 index 00000000..fe69c974 --- /dev/null +++ b/platform/3ds/audio_driver_3ds.h @@ -0,0 +1,90 @@ +/*************************************************************************/ +/* audio_driver_3ds.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 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 AUDIO_DRIVER_3DS_H +#define AUDIO_DRIVER_3DS_H + +#include "servers/audio/audio_server_sw.h" + +#include "core/os/thread.h" +#include "core/os/mutex.h" + +extern "C" { +#include <3ds/types.h> +#include <3ds/ndsp/ndsp.h> +#include <3ds/ndsp/channel.h> +#include <3ds/allocator/linear.h> +#include <3ds/services/dsp.h> +} + + +class AudioDriver3ds : public AudioDriverSW { + + enum { + NDSP_BUFFER_COUNT = 3, + }; + + Thread* thread; + Mutex* mutex; + + int32_t* samples_in; + + ndspWaveBuf ndsp_buffers[NDSP_BUFFER_COUNT]; + + static void thread_func(void* p_udata); + int buffer_size; + + unsigned int mix_rate; + OutputFormat output_format; + + int channels; + + bool active; + bool thread_exited; + mutable bool exit_thread; + bool pcm_open; + +public: + + const char* get_name() const { + return "3DS NDSP"; + }; + + virtual Error init(); + virtual void start(); + virtual int get_mix_rate() const; + virtual OutputFormat get_output_format() const; + virtual void lock(); + virtual void unlock(); + virtual void finish(); + + AudioDriver3ds(); + ~AudioDriver3ds(); +}; + +#endif diff --git a/platform/3ds/detect.py b/platform/3ds/detect.py new file mode 100644 index 00000000..3af00e3e --- /dev/null +++ b/platform/3ds/detect.py @@ -0,0 +1,92 @@ + +import os +import sys + + +def is_active(): + return True + + +def get_name(): + return "Server" + + +def can_build(): + if (os.name!="posix"): + return False + + return True # enabled + + +def get_opts(): + return [] + + +def get_flags(): + return [ + ('builtin_zlib', 'no'), + ('theora','no'), #use builtin openssl + ] + +def build_shader_gen(target, source, env, for_signature): + return "picasso -o {} {}".format(target[0], source[0]) + + +def build_shader_header(target, source, env): + import os + data = source[0].get_contents() + data_str = ",".join([str(x) for x in data]) + name = os.path.basename(str(target[0]))[:-2] + target[0].prepare() + with open(str(target[0]), 'w') as f: + f.write("/* Auto-generated from {} */\n".format(str(source[0]))) + f.write("static uint8_t shader_builtin_{}[] =\n{{{}}};".format( + name, data_str)) + + +def configure(env): + + env.Append(CPPPATH=['#platform/3ds']) + + devkit_path = os.environ["DEVKITPRO"] + dev_path = os.environ["DEVKITARM"] + + + env.Append(BUILDERS={'PICA': env.Builder(generator=build_shader_gen, suffix='.shbin', src_suffix='.pica')}) + env.Append(BUILDERS={'PICA_HEADER': env.Builder(action=build_shader_header, suffix='.h', src_suffix='.shbin')}) + + + env["CC"]=dev_path+"/bin/arm-none-eabi-gcc" + env["CXX"]=dev_path+"/bin/arm-none-eabi-g++" + env["LD"]=dev_path+"/bin/arm-none-eabi-g++" + env["AR"]=dev_path+"/bin/arm-none-eabi-ar" + env["AS"]=dev_path+"/bin/arm-none-eabi-as" + env["RANLIB"]=dev_path+"/bin/arm-none-eabi-ranlib" + + env["bits"]="32" + + + + arch = ['-march=armv6k', '-mtune=mpcore','-mfloat-abi=hard','-mtp=soft' ] + + env.Append(CPPPATH=[dev_path+"/arm-none-eabi/include/", devkit_path+"/portlibs/3ds/include/", devkit_path+"/libctru/include/"]) + env.Append(LIBPATH=[dev_path+"/arm-none-eabi/lib/armv6k/fpu/", devkit_path+"/portlibs/3ds/lib/", devkit_path+"/libctru/lib/"]) + + + + if env["target"]=="release": + env.Append(CCFLAGS=['-mword-relocations','-ffunction-sections', '-fno-rtti', '-fno-exceptions']+arch) + elif env["target"]=="release_debug": + env.Append(CCFLAGS=['-O2','-ffast-math','-DDEBUG_ENABLED']) + elif env["target"]=="debug": + env.Append(CCFLAGS=['-g2', '-Wall','-DDEBUG_ENABLED','-DDEBUG_MEMORY_ENABLED']) + + env.Append(CCFLAGS=['-D__3DS__','-DNEED_LONG_INT', '-D_3DS_ENABLED', '-DNO_THREADS','-DNO_SAFE_CAST']) + env.Append(LIBS=['pthread', 'z', 'citro3d', 'ctru']) + env.Append(LINKFLAGS=['-specs=3dsx.specs', '-g'] + arch) + + if (env["CXX"]=="clang++"): + env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND']) + env["CC"]="clang" + env["LD"]="clang++" + diff --git a/platform/3ds/godot_3ds.cpp b/platform/3ds/godot_3ds.cpp new file mode 100644 index 00000000..ad1bac29 --- /dev/null +++ b/platform/3ds/godot_3ds.cpp @@ -0,0 +1,62 @@ +/*************************************************************************/ +/* godot_server.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 "main/main.h" +#include "os_3ds.h" + + +extern "C" { +#include <3ds/gfx.h> +#include <3ds/os.h> +#include <3ds/console.h> +u32 __stacksize__ = 1024 * 128; +}; + +int main(int argc, char* argv[]) { + + gfxInitDefault(); + gfxSetDoubleBuffering(GFX_TOP, true); + consoleInit(GFX_BOTTOM, NULL); + osSetSpeedupEnable(true); + + OS_3DS os; + + char* args[] = {"-path", "./fe"}; + + Error err = Main::setup("3ds", 2, args, true); + if (err!=OK) + return 255; + + if (Main::start()) { + printf("game running\n"); + os.run(); // it is actually the OS that decides how to run + } + Main::cleanup(); + + return 0; +} diff --git a/platform/3ds/logo.png b/platform/3ds/logo.png new file mode 100644 index 00000000..6b749009 Binary files /dev/null and b/platform/3ds/logo.png differ diff --git a/platform/3ds/os_3ds.cpp b/platform/3ds/os_3ds.cpp new file mode 100644 index 00000000..860b73be --- /dev/null +++ b/platform/3ds/os_3ds.cpp @@ -0,0 +1,407 @@ +/*************************************************************************/ +/* OS_3DS.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 "servers/visual/visual_server_raster.h" +#include "rasterizer_3ds.h" + +#include "os_3ds.h" +#include +#include +#include "print_string.h" +#include "servers/physics/physics_server_sw.h" +#include "drivers/unix/memory_pool_static_malloc.h" +#include "drivers/unix/dir_access_unix.h" +#include "drivers/unix/file_access_unix.h" +#include "os/memory_pool_dynamic_static.h" +#include "core/os/thread_dummy.h" +#include "main/main.h" +#include +#include +#include "thread_3ds.h" +#include "drivers/unix/tcp_server_posix.h" +#include "drivers/unix/stream_peer_tcp_posix.h" +// #include "packet_peer_udp_posix.h" +#include +#include "drivers/unix/ip_unix.h" +extern "C" { +#include <3ds/services/hid.h> +#include <3ds/services/soc.h> +#include <3ds/services/sslc.h> +}; + +#define SOC_ALIGN 0x1000 +#define SOC_BUFFERSIZE 0x100000 + + + +/* +void socShutdown() { + + printf("waiting for socExit...\n"); + socExit(); + +}*/ + + + + // atexit(socShutdown); + +int OS_3DS::get_video_driver_count() const { + + return 1; +} +const char * OS_3DS::get_video_driver_name(int p_driver) const { + + return "citro3D"; +} +OS::VideoMode OS_3DS::get_default_video_mode() const { + + return OS::VideoMode(800,480,false); +} + +static MemoryPoolStaticMalloc *mempool_static=NULL; +static MemoryPoolDynamicStatic *mempool_dynamic=NULL; +static u32 *SOC_buffer = NULL; + +void OS_3DS::initialize_core() { + + + //TODO: Make audio single threaded so I don't need threads + Thread3ds::make_default(); + SemaphoreDummy::make_default(); + MutexDummy::make_default(); + + FileAccess::make_default(FileAccess::ACCESS_RESOURCES); + FileAccess::make_default(FileAccess::ACCESS_USERDATA); + FileAccess::make_default(FileAccess::ACCESS_FILESYSTEM); + //FileAccessBufferedFA::make_default(); + DirAccess::make_default(DirAccess::ACCESS_RESOURCES); + DirAccess::make_default(DirAccess::ACCESS_USERDATA); + DirAccess::make_default(DirAccess::ACCESS_FILESYSTEM); + + + mempool_static = new MemoryPoolStaticMalloc; + mempool_dynamic = memnew( MemoryPoolDynamicStatic ); + + ticks_start = 0; + ticks_start = get_ticks_usec(); +/* + FileAccess::make_default(FileAccess::ACCESS_RESOURCES); + FileAccess::make_default(FileAccess::ACCESS_USERDATA); + FileAccess::make_default(FileAccess::ACCESS_FILESYSTEM); + //FileAccessBufferedFA::make_default(); + DirAccess::make_default(DirAccess::ACCESS_RESOURCES); + DirAccess::make_default(DirAccess::ACCESS_USERDATA); + DirAccess::make_default(DirAccess::ACCESS_FILESYSTEM);*/ + + SOC_buffer = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE); + + if(SOC_buffer == NULL) { + printf("memalign: failed to allocate\n"); + } + int ret; + if ((ret = socInit(SOC_buffer, SOC_BUFFERSIZE)) != 0) { + printf("socInit: 0x%08X\n", (unsigned int)ret); + } + sslcInit(0); + + TCPServerPosix::make_default(); + StreamPeerTCPPosix::make_default(); + // PacketPeerUDPPosix::make_default(); + IP_Unix::make_default(); +} + +void OS_3DS::finalize_core() { + if (mempool_dynamic) + memdelete( mempool_dynamic ); + delete mempool_static; +} + +void OS_3DS::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) { + + args=OS::get_singleton()->get_cmdline_args(); + current_videomode=p_desired; + main_loop=NULL; + + + rasterizer = memnew( Rasterizer3DS ); + + visual_server = memnew( VisualServerRaster(rasterizer) ); + + AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton(); + + if (AudioDriverManagerSW::get_driver(p_audio_driver)->init()!=OK) { + + ERR_PRINT("Initializing audio failed."); + } + + sample_manager = memnew( SampleManagerMallocSW ); + audio_server = memnew( AudioServerSW(sample_manager) ); + audio_server->init(); + spatial_sound_server = memnew( SpatialSoundServerSW ); + spatial_sound_server->init(); + spatial_sound_2d_server = memnew( SpatialSound2DServerSW ); + spatial_sound_2d_server->init(); + + + ERR_FAIL_COND(!visual_server); + + visual_server->init(); + // + physics_server = memnew( PhysicsServerSW ); + physics_server->init(); + physics_2d_server = memnew( Physics2DServerSW ); + physics_2d_server->init(); + + input = memnew( InputDefault ); + +} +void OS_3DS::finalize() { + + if(main_loop) + memdelete(main_loop); + main_loop=NULL; + + spatial_sound_server->finish(); + memdelete(spatial_sound_server); + spatial_sound_2d_server->finish(); + memdelete(spatial_sound_2d_server); + + //if (debugger_connection_console) { +// memdelete(debugger_connection_console); +//} + + audio_server->finish(); + memdelete(audio_server); + memdelete(sample_manager); + + visual_server->finish(); + memdelete(visual_server); + memdelete(rasterizer); + + physics_server->finish(); + memdelete(physics_server); + + physics_2d_server->finish(); + memdelete(physics_2d_server); + + memdelete(input); + + args.clear(); +} + +void OS_3DS::set_mouse_show(bool p_show) { + + +} +void OS_3DS::set_mouse_grab(bool p_grab) { + + grab=p_grab; +} +bool OS_3DS::is_mouse_grab_enabled() const { + + return grab; +} + +int OS_3DS::get_mouse_button_state() const { + + return 0; +} + +Point2 OS_3DS::get_mouse_pos() const { + + return Point2(); +} + +void OS_3DS::set_window_title(const String& p_title) { + + +} + +void OS_3DS::set_video_mode(const VideoMode& p_video_mode,int p_screen) { + + +} + +OS::Date OS_3DS::get_date() const { + Date ret; + return ret; +} + +OS::Time OS_3DS::get_time() const { + Time ret; + return ret; +} + + +void OS_3DS::delay_usec(uint32_t p_usec) const{ + usleep(p_usec); +} + +uint64_t OS_3DS::get_ticks_usec() const{ + struct timeval tv_now; + gettimeofday(&tv_now, NULL); + + uint64_t longtime = (uint64_t)tv_now.tv_usec + (uint64_t)tv_now.tv_sec * 1000000L; + longtime -= ticks_start; + + return longtime; +} + +OS::VideoMode OS_3DS::get_video_mode(int p_screen) const { + + return current_videomode; +} +void OS_3DS::get_fullscreen_mode_list(List *p_list,int p_screen) const { + + +} + + +MainLoop *OS_3DS::get_main_loop() const { + + return main_loop; +} + +void OS_3DS::delete_main_loop() { + + if (main_loop) + memdelete(main_loop); + main_loop=NULL; +} + +void OS_3DS::set_main_loop( MainLoop * p_main_loop ) { + + main_loop=p_main_loop; + input->set_main_loop(p_main_loop); +} + +bool OS_3DS::can_draw() const { + + return true; +}; + + +String OS_3DS::get_name() { + + return "Nintendo 3DS"; +} + + + +void OS_3DS::move_window_to_foreground() { + +} + +void OS_3DS::set_cursor_shape(CursorShape p_shape) { + + +} + +static u32 buttons[16] = { + KEY_B, + KEY_A, + KEY_Y, + KEY_X, + KEY_L, + KEY_R, + KEY_ZL, // L2 + KEY_ZR, // R2 + KEY_TOUCH, + KEY_TOUCH, + KEY_SELECT, + KEY_START, + KEY_DUP, + KEY_DDOWN, + KEY_DLEFT, + KEY_DRIGHT, +}; + +void OS_3DS::process_keys() { + hidScanInput(); + + last++; + + u32 down = hidKeysDown(); + + for(int i = 0; i < 16; i++) { + if (down & buttons[i]) { + InputEvent event; + event.type = InputEvent::JOYSTICK_BUTTON; + event.device = 0; + event.joy_button.button_index = i; + event.joy_button.pressed = true; + event.ID = last; + input->parse_input_event(event); + } else { + InputEvent event; + event.type = InputEvent::JOYSTICK_BUTTON; + event.device = 0; + event.joy_button.button_index = i; + event.joy_button.pressed = false; + event.ID = last; + input->parse_input_event(event); + } + } + + circlePosition pos; + hidCircleRead(&pos); + + input->set_joy_axis(0, 0, pos.dx); + input->set_joy_axis(0, 1, pos.dy); +} + +void OS_3DS::run() { + + force_quit = false; + + if (!main_loop) + return; + + main_loop->init(); + + while (!force_quit) { + process_keys(); + + if (Main::iteration()==true) + break; + }; + + main_loop->finish(); +} + +void OS_3DS::swap_buffers() { +} + +OS_3DS::OS_3DS() { + + AudioDriverManagerSW::add_driver(&driver_3ds); + //adriver here + grab=false; + +}; diff --git a/platform/3ds/os_3ds.h b/platform/3ds/os_3ds.h new file mode 100644 index 00000000..d863252b --- /dev/null +++ b/platform/3ds/os_3ds.h @@ -0,0 +1,146 @@ +/*************************************************************************/ +/* os_server.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 OS_3DS_H +#define OS_3DS_H + +#include "os/input.h" +#include "drivers/unix/os_unix.h" +#include "servers/visual_server.h" +#include "servers/visual/rasterizer.h" +#include "servers/audio/audio_driver_dummy.h" +#include "servers/physics_server.h" +#include "servers/audio/audio_server_sw.h" +#include "servers/audio/sample_manager_sw.h" +#include "servers/spatial_sound/spatial_sound_server_sw.h" +#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h" +#include "drivers/rtaudio/audio_driver_rtaudio.h" +#include "servers/physics_2d/physics_2d_server_sw.h" +#include "audio_driver_3ds.h" +#undef CursorShape + +class OS_3DS : public OS { + + Rasterizer *rasterizer; + VisualServer *visual_server; + VideoMode current_videomode; + List args; + MainLoop *main_loop; + + + AudioDriver3ds driver_3ds; + bool grab; + uint64_t ticks_start; + + + PhysicsServer *physics_server; + Physics2DServer *physics_2d_server; + + virtual void delete_main_loop(); + // IP_Unix *ip_unix; + + AudioServerSW *audio_server; + SampleManagerMallocSW *sample_manager; + SpatialSoundServerSW *spatial_sound_server; + SpatialSound2DServerSW *spatial_sound_2d_server; + + bool force_quit; + + int last; + + InputDefault *input; + + + +protected: + + virtual int get_video_driver_count() const; + virtual const char * get_video_driver_name(int p_driver) const; + virtual VideoMode get_default_video_mode() const; + + virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver); + virtual void finalize(); + + virtual void set_main_loop( MainLoop * p_main_loop ); + +public: + virtual void initialize_core(); + virtual void finalize_core(); + virtual String get_name(); + + virtual void set_cursor_shape(CursorShape p_shape); + + virtual int get_audio_driver_count() const { return 1; }; + virtual const char * get_audio_driver_name(int p_driver) const { return "Dummy"; }; + virtual void vprint(const char* p_format, va_list p_list, bool p_stderr=false) { if (p_stderr) { + + vfprintf(stderr,p_format,p_list); + fflush(stderr); + } else { + + vprintf(p_format,p_list); + fflush(stdout); + }}; + virtual void alert(const String& p_alert,const String& p_title="ALERT!") {}; + virtual String get_stdin_string(bool p_block = true) { return ""; }; + virtual Error execute(const String& p_path, const List& p_arguments,bool p_blocking,ProcessID *r_child_id=NULL,String* r_pipe=NULL,int *r_exitcode=NULL) { return FAILED; }; + virtual Error kill(const ProcessID& p_pid) { return FAILED; }; + virtual bool has_environment(const String& p_var) const { return false; }; + virtual String get_environment(const String& p_var) const { return ""; }; + virtual Date get_date() const; + virtual Time get_time() const; + // virtual TimeZoneInfo get_time_zone_info() const; + virtual void delay_usec(uint32_t p_usec) const; + virtual uint64_t get_ticks_usec() const; + + virtual void process_keys(); + + virtual void set_mouse_show(bool p_show); + virtual void set_mouse_grab(bool p_grab); + virtual bool is_mouse_grab_enabled() const; + virtual Point2 get_mouse_pos() const; + virtual int get_mouse_button_state() const; + virtual void set_window_title(const String& p_title); + + virtual MainLoop *get_main_loop() const; + + virtual bool can_draw() const; + + virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0); + virtual VideoMode get_video_mode(int p_screen=0) const; + virtual void get_fullscreen_mode_list(List *p_list,int p_screen=0) const; + + virtual void move_window_to_foreground(); + virtual void swap_buffers(); + + void run(); + + OS_3DS(); +}; + +#endif diff --git a/platform/3ds/platform_config.h b/platform/3ds/platform_config.h new file mode 100644 index 00000000..1bb5afb0 --- /dev/null +++ b/platform/3ds/platform_config.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* platform_config.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. */ +/*************************************************************************/ +#include + diff --git a/platform/3ds/rasterizer_3ds Kopie Kopie.cpp b/platform/3ds/rasterizer_3ds Kopie Kopie.cpp new file mode 100644 index 00000000..c6d92e1e --- /dev/null +++ b/platform/3ds/rasterizer_3ds Kopie Kopie.cpp @@ -0,0 +1,2268 @@ +/*************************************************************************/ +/* rasterizer_3ds.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 "rasterizer_3ds.h" +#include "shaders/simple_3d.h" +#include "shaders/simple_2d.h" + +static const vertex3ds vertex_list[] = +{ + { 200.0f, 200.0f, 0.5f }, + { 100.0f, 40.0f, 0.5f }, + { 300.0f, 40.0f, 0.5f }, +}; + +#define vertex_list_count (sizeof(vertex_list)/sizeof(vertex_list[0])) + +#define DISPLAY_TRANSFER_FLAGS \ + (GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | GX_TRANSFER_RAW_COPY(0) | \ + GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | \ + GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO)) + + +#define TEXTURE_TRANSFER_FLAGS (GX_TRANSFER_FLIP_VERT(1) | GX_TRANSFER_OUT_TILED(1) | GX_TRANSFER_RAW_COPY(0) | GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | \ + GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO)) + + +void _set_uniform(int uniform_location, const Matrix32& p_transform) +{ + const Matrix32& tr = p_transform; + + C3D_Mtx mtx; + + float matrix[16] = { /* build a 16x16 matrix */ + tr.elements[2][0], 0, tr.elements[1][0], tr.elements[0][0], + tr.elements[2][1], 0, tr.elements[1][1], tr.elements[0][1], + 0, 1, 0, 0, + 1, 0, 0, 0, + }; + + memcpy(mtx.m, matrix, sizeof(matrix)); + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uniform_location, &mtx); +} + +void _set_uniform(int uniform_location, const CameraMatrix& p_matrix) +{ + // Swap X/Y axis due to 3DS screens being sideways + // and adjust clipping range from [-1, 1] to [-1, 0] + float m[16] = { + 0, -1, 0, 0, + 1, 0, 0, 0, + 0, 0, 0.5, 0, + 0, 0, -0.5, 1, + }; + + CameraMatrix p = *reinterpret_cast(m) * p_matrix; + + C3D_Mtx mtx; + float *to = mtx.m; + const float *from = reinterpret_cast(p.matrix); + + + to[0] = from[12]; + to[1] = from[8]; + to[2] = from[4]; + to[3] = from[0]; + to[4] = from[13]; + to[5] = from[9]; + to[6] = from[5]; + to[7] = from[1]; + to[8] = from[14]; + to[9] = from[10]; + to[10] = from[6]; + to[11] = from[2]; + to[12] = from[15]; + to[13] = from[11]; + to[14] = from[7]; + to[15] = from[3]; + + + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uniform_location, &mtx); +} + +/* TEXTURE API */ + + +RID Rasterizer3DS::texture_create() { + + Texture *texture = memnew(Texture); + ERR_FAIL_COND_V(!texture,RID()); + return texture_owner.make_rid( texture ); + +} + +void Rasterizer3DS::texture_allocate(RID p_texture,int p_width, int p_height,Image::Format p_format,uint32_t p_flags) { + + + Texture *texture = texture_owner.get( p_texture ); + ERR_FAIL_COND(!texture); + C3D_TexInit(&texture->texture, p_width, p_height, GPU_RGBA8); + texture->width=p_width; + texture->height=p_height; + texture->format=p_format; + texture->flags=p_flags; +} + +void Rasterizer3DS::texture_set_data(RID p_texture,const Image& p_image,VS::CubeMapSide p_cube_side) { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND(!texture); + ERR_FAIL_COND(texture->format != p_image.get_format() ); + + texture->image[p_cube_side]=p_image; + + DVector d = p_image.get_data(); + const u32* buffer = reinterpret_cast(d.read().ptr()); + u8 * gpuBuffer = (u8 *)linearAlloc(texture->width * texture->height * 4); + + u32 * src = (u32 *)buffer; + u32 * dst = (u32 *)gpuBuffer; + + for (unsigned y = 0; y < texture->height; y++) + { + for (unsigned x = 0; x < texture->width; x++) + { + u32 clr = *src; + // *dst = __builtin_bswap32(clr); + *dst = 0x0; + } + dst += 4; + } + + GSPGPU_FlushDataCache((u32 *)gpuBuffer, texture->width * texture->height * 4); + + C3D_SyncDisplayTransfer((u32 *)gpuBuffer, GX_BUFFER_DIM(texture->width, texture->height), (u32 *)texture->texture.data, GX_BUFFER_DIM(texture->width, texture->height), TEXTURE_TRANSFER_FLAGS); + + // gspWaitForPPF(); + C3D_TexSetFilter(&texture->texture, GPU_LINEAR, GPU_NEAREST); + C3D_TexBind(0, &texture->texture); + + linearFree(gpuBuffer); + + C3D_TexEnv* env = C3D_GetTexEnv(0); + C3D_TexEnvInit(env); + C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, (GPU_TEVSRC)0, (GPU_TEVSRC)0); + C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE); + + +} + +Image Rasterizer3DS::texture_get_data(RID p_texture,VS::CubeMapSide p_cube_side) const { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,Image()); + + return texture->image[p_cube_side]; +} + +void Rasterizer3DS::texture_set_flags(RID p_texture,uint32_t p_flags) { + + Texture *texture = texture_owner.get( p_texture ); + ERR_FAIL_COND(!texture); + uint32_t cube = texture->flags & VS::TEXTURE_FLAG_CUBEMAP; + texture->flags=p_flags|cube; // can't remove a cube from being a cube + +} +uint32_t Rasterizer3DS::texture_get_flags(RID p_texture) const { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,0); + + return texture->flags; + +} +Image::Format Rasterizer3DS::texture_get_format(RID p_texture) const { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,Image::FORMAT_GRAYSCALE); + + return texture->format; +} +uint32_t Rasterizer3DS::texture_get_width(RID p_texture) const { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,0); + + return texture->width; +} +uint32_t Rasterizer3DS::texture_get_height(RID p_texture) const { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,0); + + return texture->height; +} + +bool Rasterizer3DS::texture_has_alpha(RID p_texture) const { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,0); + + return false; + +} + +void Rasterizer3DS::texture_set_size_override(RID p_texture,int p_width, int p_height) { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND(!texture); + + ERR_FAIL_COND(p_width<=0 || p_width>4096); + ERR_FAIL_COND(p_height<=0 || p_height>4096); + //real texture size is in alloc width and height +// texture->width=p_width; +// texture->height=p_height; + +} + +void Rasterizer3DS::texture_set_reload_hook(RID p_texture,ObjectID p_owner,const StringName& p_function) const { + + +} + +static void _draw_primitive(int p_points, const Vector3 *p_vertices, const Vector3 *p_normals, const Color* p_colors, const Vector3 *p_uvs,const Plane *p_tangents=NULL,int p_instanced=1) { + ERR_FAIL_COND(!p_vertices); + ERR_FAIL_COND(p_points <1 || p_points>4); + + // int type = prim_type[p_points - 1]; + + C3D_BufInfo* bufInfo = C3D_GetBufInfo(); + BufInfo_Init(bufInfo); + BufInfo_Add(bufInfo, p_vertices, sizeof(Vector3), 2, 0x10); + + C3D_DrawArrays(GPU_TRIANGLE_FAN, 0, 4); +}; +//--------------------------------------------------------------------------------- +static void drawSpriteImmediate( size_t idx, int x, int y, int width, int height ) { +//--------------------------------------------------------------------------------- + + float left = 0;//images[image].left; + float right = 0.5;//images[image].right; + float top = 0;//images[image].top; + float bottom = 0.5;//images[image].bottom; + + if (idx > 500) + return; + + // Draw a textured quad directly + C3D_ImmDrawBegin(GPU_TRIANGLE_STRIP); + C3D_ImmSendAttrib(x, y, 0.5f, 0.0f); // v0=position + C3D_ImmSendAttrib( left, top, 0.0f, 0.0f); + + C3D_ImmSendAttrib(x, y+height, 0.5f, 0.0f); + C3D_ImmSendAttrib( left, bottom, 0.0f, 0.0f); + + C3D_ImmSendAttrib(x+width, y, 0.5f, 0.0f); + C3D_ImmSendAttrib( right, top, 0.0f, 0.0f); + + C3D_ImmSendAttrib(x+width, y+height, 0.5f, 0.0f); + C3D_ImmSendAttrib( right, bottom, 0.0f, 0.0f); + C3D_ImmDrawEnd(); +} +void Rasterizer3DS::_draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_flip_h=false,bool p_flip_v=false ) { + VertexArray dscoords[4]= { + {Vector3( p_src_region.pos.x/p_tex_size.width, + p_src_region.pos.y/p_tex_size.height, 0), + Vector2( p_rect.pos.x, p_rect.pos.y )}, + + + {Vector3((p_src_region.pos.x+p_src_region.size.width)/p_tex_size.width, + p_src_region.pos.y/p_tex_size.height, 0), + Vector2( p_rect.pos.x+p_rect.size.width, p_rect.pos.y )}, + + {Vector3( (p_src_region.pos.x+p_src_region.size.width)/p_tex_size.width, + (p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height, 0), + Vector2( p_rect.pos.x+p_rect.size.width, p_rect.pos.y+p_rect.size.height )}, + + {Vector3( p_src_region.pos.x/p_tex_size.width, + (p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height, 0), + Vector2( p_rect.pos.x,p_rect.pos.y+p_rect.size.height )} + }; + + VertexArray dscoords23[4]= { + {Vector3( 0, + 0, 0), + Vector2( p_rect.pos.x, p_rect.pos.y )}, + + + {Vector3(5, + 0, 0), + Vector2( p_rect.pos.x+p_rect.size.width, p_rect.pos.y )}, + + {Vector3( 0, + 5, 0), + Vector2( p_rect.pos.x+p_rect.size.width, p_rect.pos.y+p_rect.size.height )}, + + {Vector3( 5, + 5, 0), + Vector2( p_rect.pos.x,p_rect.pos.y+p_rect.size.height )} + }; + + + if (p_flip_h) { + SWAP( dscoords[0], dscoords[1] ); + SWAP( dscoords[2], dscoords[3] ); + } + if (p_flip_v) { + SWAP( dscoords[1], dscoords[2] ); + SWAP( dscoords[0], dscoords[3] ); + } + + Vector3 coords[4]= { + + }; + + // void* vbo_data = linearAlloc(sizeof(dscoords)); + // memcpy(vbo_data, dscoords, sizeof(dscoords)); + // memcpy(vbo_data+sizeof(coords), texcoords, sizeof(texcoords)); + /* + C3D_AttrInfo* attrInfo = C3D_GetAttrInfo(); + AttrInfo_Init(attrInfo); + AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position + AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2); // v1=color + + C3D_BufInfo* bufInfo = C3D_GetBufInfo(); + BufInfo_Init(bufInfo); + BufInfo_Add(bufInfo, dscoords, sizeof(VertexArray), 2, 0x10); + + C3D_DrawArrays(GPU_TRIANGLE_STRIP, 0, sizeof(dscoords));*/ +/* + C3D_ImmDrawBegin(GPU_TRIANGLE_STRIP); + C3D_ImmSendAttrib(p_src_region.pos.x/p_tex_size.width, p_src_region.pos.y/p_tex_size.height, 0.5f, 0.0f); // v0=position + C3D_ImmSendAttrib(p_rect.pos.x, p_rect.pos.y, 0.0f, 0.0f); // v1=color + + C3D_ImmSendAttrib((p_src_region.pos.x+p_src_region.size.width)/p_tex_size.width, p_src_region.pos.y/p_tex_size.height, 0.5f, 0.0f); + C3D_ImmSendAttrib(p_rect.pos.x+p_rect.size.width, p_rect.pos.y, 0.0f, 0.0f); + + C3D_ImmSendAttrib((p_src_region.pos.x+p_src_region.size.width)/p_tex_size.width, (p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height, 0.5f, 0.0f); + C3D_ImmSendAttrib(p_rect.pos.x+p_rect.size.width, p_rect.pos.y+p_rect.size.height, 0.0f, 0.0f); + + C3D_ImmSendAttrib(p_src_region.pos.x/p_tex_size.width, (p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height, 0.5f, 0.0f); + C3D_ImmSendAttrib(p_rect.pos.x, p_rect.pos.y+p_rect.size.height, 0.0f, 0.0f); + + C3D_ImmDrawEnd();*/ + + // drawSpriteImmediate(0, 0, 0, 32, 32); + C3D_DrawArrays(GPU_TRIANGLES, 0, vertex_list_count); + + // Mtx_Identity(&modelView); + + // Mtx_Translate(&modelView, 0.0, 0.0, -2.5, true); + + // C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView); + + // Draw the triangle directly + + + // _draw_primitive(4,coords,0,0,texcoords); + + // linearFree(vbo_data); +} + +/* SHADER API */ + +/* SHADER API */ + +RID Rasterizer3DS::shader_create(VS::ShaderMode p_mode) { + + Shader *shader = memnew( Shader ); + shader->mode=p_mode; + shader->fragment_line=0; + shader->vertex_line=0; + shader->light_line=0; + RID rid = shader_owner.make_rid(shader); + + return rid; + +} + + + +void Rasterizer3DS::shader_set_mode(RID p_shader,VS::ShaderMode p_mode) { + + ERR_FAIL_INDEX(p_mode,3); + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND(!shader); + shader->mode=p_mode; + +} +VS::ShaderMode Rasterizer3DS::shader_get_mode(RID p_shader) const { + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND_V(!shader,VS::SHADER_MATERIAL); + return shader->mode; +} + +void Rasterizer3DS::shader_set_code(RID p_shader, const String& p_vertex, const String& p_fragment,const String& p_light,int p_vertex_ofs,int p_fragment_ofs,int p_light_ofs) { + + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND(!shader); + shader->fragment_code=p_fragment; + shader->vertex_code=p_vertex; + shader->light_code=p_light; + shader->fragment_line=p_fragment_ofs; + shader->vertex_line=p_vertex_ofs; + shader->light_line=p_vertex_ofs; + +} + + +String Rasterizer3DS::shader_get_vertex_code(RID p_shader) const { + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND_V(!shader,String()); + return shader->vertex_code; + +} + +String Rasterizer3DS::shader_get_fragment_code(RID p_shader) const { + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND_V(!shader,String()); + return shader->fragment_code; + +} + +String Rasterizer3DS::shader_get_light_code(RID p_shader) const { + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND_V(!shader,String()); + return shader->light_code; + +} + +void Rasterizer3DS::shader_get_param_list(RID p_shader, List *p_param_list) const { + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND(!shader); + +} + +/* COMMON MATERIAL API */ + + +RID Rasterizer3DS::material_create() { + + return material_owner.make_rid( memnew( Material ) ); +} + +void Rasterizer3DS::material_set_shader(RID p_material, RID p_shader) { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + material->shader=p_shader; + +} + +RID Rasterizer3DS::material_get_shader(RID p_material) const { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,RID()); + return material->shader; +} + +void Rasterizer3DS::material_set_param(RID p_material, const StringName& p_param, const Variant& p_value) { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + + if (p_value.get_type()==Variant::NIL) + material->shader_params.erase(p_param); + else + material->shader_params[p_param]=p_value; +} +Variant Rasterizer3DS::material_get_param(RID p_material, const StringName& p_param) const { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,Variant()); + + if (material->shader_params.has(p_param)) + return material->shader_params[p_param]; + else + return Variant(); +} + + +void Rasterizer3DS::material_set_flag(RID p_material, VS::MaterialFlag p_flag,bool p_enabled) { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + ERR_FAIL_INDEX(p_flag,VS::MATERIAL_FLAG_MAX); + material->flags[p_flag]=p_enabled; + +} +bool Rasterizer3DS::material_get_flag(RID p_material,VS::MaterialFlag p_flag) const { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,false); + ERR_FAIL_INDEX_V(p_flag,VS::MATERIAL_FLAG_MAX,false); + return material->flags[p_flag]; + + +} + +void Rasterizer3DS::material_set_depth_draw_mode(RID p_material, VS::MaterialDepthDrawMode p_mode) { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + material->depth_draw_mode=p_mode; +} + +VS::MaterialDepthDrawMode Rasterizer3DS::material_get_depth_draw_mode(RID p_material) const{ + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,VS::MATERIAL_DEPTH_DRAW_ALWAYS); + return material->depth_draw_mode; + +} + + +void Rasterizer3DS::material_set_blend_mode(RID p_material,VS::MaterialBlendMode p_mode) { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + material->blend_mode=p_mode; + +} +VS::MaterialBlendMode Rasterizer3DS::material_get_blend_mode(RID p_material) const { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,VS::MATERIAL_BLEND_MODE_ADD); + return material->blend_mode; +} + +void Rasterizer3DS::material_set_line_width(RID p_material,float p_line_width) { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + material->line_width=p_line_width; + +} +float Rasterizer3DS::material_get_line_width(RID p_material) const { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,0); + + return material->line_width; +} + +/* MESH API */ + + +RID Rasterizer3DS::mesh_create() { + + + return mesh_owner.make_rid( memnew( Mesh ) ); +} + + +void Rasterizer3DS::mesh_add_surface(RID p_mesh,VS::PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes,bool p_alpha_sort) { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + + ERR_FAIL_INDEX( p_primitive, VS::PRIMITIVE_MAX ); + ERR_FAIL_COND(p_arrays.size()!=VS::ARRAY_MAX); + + Surface s; + + + s.format=0; + + for(int i=0;imorph_target_count; + s.morph_format=s.format; + + + Surface *surface = memnew( Surface ); + *surface=s; + + mesh->surfaces.push_back(surface); + + +} + + + +void Rasterizer3DS::mesh_add_custom_surface(RID p_mesh,const Variant& p_dat) { + + ERR_EXPLAIN("Dummy Rasterizer does not support custom surfaces. Running on wrong platform?"); + ERR_FAIL_V(); +} + +Array Rasterizer3DS::mesh_get_surface_arrays(RID p_mesh,int p_surface) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,Array()); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Array() ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, Array() ); + + return surface->data; + + +} +Array Rasterizer3DS::mesh_get_surface_morph_arrays(RID p_mesh,int p_surface) const{ + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,Array()); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Array() ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, Array() ); + + return surface->morph_data; + +} + + +void Rasterizer3DS::mesh_set_morph_target_count(RID p_mesh,int p_amount) { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + ERR_FAIL_COND( mesh->surfaces.size()!=0 ); + + mesh->morph_target_count=p_amount; + +} + +int Rasterizer3DS::mesh_get_morph_target_count(RID p_mesh) const{ + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,-1); + + return mesh->morph_target_count; + +} + +void Rasterizer3DS::mesh_set_morph_target_mode(RID p_mesh,VS::MorphTargetMode p_mode) { + + ERR_FAIL_INDEX(p_mode,2); + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + + mesh->morph_target_mode=p_mode; + +} + +VS::MorphTargetMode Rasterizer3DS::mesh_get_morph_target_mode(RID p_mesh) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,VS::MORPH_MODE_NORMALIZED); + + return mesh->morph_target_mode; + +} + + + +void Rasterizer3DS::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material,bool p_owned) { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + ERR_FAIL_INDEX(p_surface, mesh->surfaces.size() ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND( !surface); + + if (surface->material_owned && surface->material.is_valid()) + free(surface->material); + + surface->material_owned=p_owned; + surface->material=p_material; +} + +RID Rasterizer3DS::mesh_surface_get_material(RID p_mesh, int p_surface) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,RID()); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), RID() ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, RID() ); + + return surface->material; +} + +int Rasterizer3DS::mesh_surface_get_array_len(RID p_mesh, int p_surface) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,-1); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), -1 ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, -1 ); + + Vector3Array arr = surface->data[VS::ARRAY_VERTEX]; + return arr.size(); + +} + +int Rasterizer3DS::mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,-1); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), -1 ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, -1 ); + + IntArray arr = surface->data[VS::ARRAY_INDEX]; + return arr.size(); + +} +uint32_t Rasterizer3DS::mesh_surface_get_format(RID p_mesh, int p_surface) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,0); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), 0 ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, 0 ); + + return surface->format; +} +VS::PrimitiveType Rasterizer3DS::mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,VS::PRIMITIVE_POINTS); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), VS::PRIMITIVE_POINTS ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, VS::PRIMITIVE_POINTS ); + + return surface->primitive; +} + +void Rasterizer3DS::mesh_remove_surface(RID p_mesh,int p_index) { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + ERR_FAIL_INDEX(p_index, mesh->surfaces.size() ); + Surface *surface = mesh->surfaces[p_index]; + ERR_FAIL_COND( !surface); + + memdelete( mesh->surfaces[p_index] ); + mesh->surfaces.remove(p_index); + +} +int Rasterizer3DS::mesh_get_surface_count(RID p_mesh) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,-1); + + return mesh->surfaces.size(); +} + +AABB Rasterizer3DS::mesh_get_aabb(RID p_mesh,RID p_skeleton) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,AABB()); + + AABB aabb; + + for (int i=0;isurfaces.size();i++) { + + if (i==0) + aabb=mesh->surfaces[i]->aabb; + else + aabb.merge_with(mesh->surfaces[i]->aabb); + } + + return aabb; +} + +void Rasterizer3DS::mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb) { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + + mesh->custom_aabb=p_aabb; +} + +AABB Rasterizer3DS::mesh_get_custom_aabb(RID p_mesh) const { + + const Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,AABB()); + + return mesh->custom_aabb; + +} + +/* MULTIMESH API */ + +RID Rasterizer3DS::multimesh_create() { + + return multimesh_owner.make_rid( memnew( MultiMesh )); +} + +void Rasterizer3DS::multimesh_set_instance_count(RID p_multimesh,int p_count) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh); + + multimesh->elements.clear(); // make sure to delete everything, so it "fails" in all implementations + multimesh->elements.resize(p_count); + +} +int Rasterizer3DS::multimesh_get_instance_count(RID p_multimesh) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,-1); + + return multimesh->elements.size(); +} + +void Rasterizer3DS::multimesh_set_mesh(RID p_multimesh,RID p_mesh) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh); + + multimesh->mesh=p_mesh; + +} +void Rasterizer3DS::multimesh_set_aabb(RID p_multimesh,const AABB& p_aabb) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh); + multimesh->aabb=p_aabb; +} +void Rasterizer3DS::multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh); + ERR_FAIL_INDEX(p_index,multimesh->elements.size()); + multimesh->elements[p_index].xform=p_transform; + +} +void Rasterizer3DS::multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh) + ERR_FAIL_INDEX(p_index,multimesh->elements.size()); + multimesh->elements[p_index].color=p_color; + +} + +RID Rasterizer3DS::multimesh_get_mesh(RID p_multimesh) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,RID()); + + return multimesh->mesh; +} +AABB Rasterizer3DS::multimesh_get_aabb(RID p_multimesh) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,AABB()); + + return multimesh->aabb; +} + +Transform Rasterizer3DS::multimesh_instance_get_transform(RID p_multimesh,int p_index) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,Transform()); + + ERR_FAIL_INDEX_V(p_index,multimesh->elements.size(),Transform()); + + return multimesh->elements[p_index].xform; + +} +Color Rasterizer3DS::multimesh_instance_get_color(RID p_multimesh,int p_index) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,Color()); + ERR_FAIL_INDEX_V(p_index,multimesh->elements.size(),Color()); + + return multimesh->elements[p_index].color; +} + +void Rasterizer3DS::multimesh_set_visible_instances(RID p_multimesh,int p_visible) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh); + multimesh->visible=p_visible; + +} + +int Rasterizer3DS::multimesh_get_visible_instances(RID p_multimesh) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,-1); + return multimesh->visible; + +} + +/* IMMEDIATE API */ + + +RID Rasterizer3DS::immediate_create() { + + Immediate *im = memnew( Immediate ); + return immediate_owner.make_rid(im); + +} + +void Rasterizer3DS::immediate_begin(RID p_immediate,VS::PrimitiveType p_rimitive,RID p_texture){ + + +} +void Rasterizer3DS::immediate_vertex(RID p_immediate,const Vector3& p_vertex){ + + +} +void Rasterizer3DS::immediate_normal(RID p_immediate,const Vector3& p_normal){ + + +} +void Rasterizer3DS::immediate_tangent(RID p_immediate,const Plane& p_tangent){ + + +} +void Rasterizer3DS::immediate_color(RID p_immediate,const Color& p_color){ + + +} +void Rasterizer3DS::immediate_uv(RID p_immediate,const Vector2& tex_uv){ + + +} +void Rasterizer3DS::immediate_uv2(RID p_immediate,const Vector2& tex_uv){ + + +} + +void Rasterizer3DS::immediate_end(RID p_immediate){ + + +} +void Rasterizer3DS::immediate_clear(RID p_immediate) { + + +} + +AABB Rasterizer3DS::immediate_get_aabb(RID p_immediate) const { + + return AABB(Vector3(-1,-1,-1),Vector3(2,2,2)); +} + +void Rasterizer3DS::immediate_set_material(RID p_immediate,RID p_material) { + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + im->material=p_material; + +} + +RID Rasterizer3DS::immediate_get_material(RID p_immediate) const { + + const Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND_V(!im,RID()); + return im->material; + +} + +/* PARTICLES API */ + +RID Rasterizer3DS::particles_create() { + + Particles *particles = memnew( Particles ); + ERR_FAIL_COND_V(!particles,RID()); + return particles_owner.make_rid(particles); +} + +void Rasterizer3DS::particles_set_amount(RID p_particles, int p_amount) { + + ERR_FAIL_COND(p_amount<1); + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.amount=p_amount; + +} + +int Rasterizer3DS::particles_get_amount(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.amount; + +} + +void Rasterizer3DS::particles_set_emitting(RID p_particles, bool p_emitting) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.emitting=p_emitting;; + +} +bool Rasterizer3DS::particles_is_emitting(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,false); + return particles->data.emitting; + +} + +void Rasterizer3DS::particles_set_visibility_aabb(RID p_particles, const AABB& p_visibility) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.visibility_aabb=p_visibility; + +} + +void Rasterizer3DS::particles_set_emission_half_extents(RID p_particles, const Vector3& p_half_extents) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + + particles->data.emission_half_extents=p_half_extents; +} +Vector3 Rasterizer3DS::particles_get_emission_half_extents(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,Vector3()); + + return particles->data.emission_half_extents; +} + +void Rasterizer3DS::particles_set_emission_base_velocity(RID p_particles, const Vector3& p_base_velocity) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + + particles->data.emission_base_velocity=p_base_velocity; +} + +Vector3 Rasterizer3DS::particles_get_emission_base_velocity(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,Vector3()); + + return particles->data.emission_base_velocity; +} + + +void Rasterizer3DS::particles_set_emission_points(RID p_particles, const DVector& p_points) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + + particles->data.emission_points=p_points; +} + +DVector Rasterizer3DS::particles_get_emission_points(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,DVector()); + + return particles->data.emission_points; + +} + +void Rasterizer3DS::particles_set_gravity_normal(RID p_particles, const Vector3& p_normal) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + + particles->data.gravity_normal=p_normal; + +} +Vector3 Rasterizer3DS::particles_get_gravity_normal(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,Vector3()); + + return particles->data.gravity_normal; +} + + +AABB Rasterizer3DS::particles_get_visibility_aabb(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,AABB()); + return particles->data.visibility_aabb; + +} + +void Rasterizer3DS::particles_set_variable(RID p_particles, VS::ParticleVariable p_variable,float p_value) { + + ERR_FAIL_INDEX(p_variable,VS::PARTICLE_VAR_MAX); + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.particle_vars[p_variable]=p_value; + +} +float Rasterizer3DS::particles_get_variable(RID p_particles, VS::ParticleVariable p_variable) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.particle_vars[p_variable]; +} + +void Rasterizer3DS::particles_set_randomness(RID p_particles, VS::ParticleVariable p_variable,float p_randomness) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.particle_randomness[p_variable]=p_randomness; + +} +float Rasterizer3DS::particles_get_randomness(RID p_particles, VS::ParticleVariable p_variable) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.particle_randomness[p_variable]; + +} + +void Rasterizer3DS::particles_set_color_phases(RID p_particles, int p_phases) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + ERR_FAIL_COND( p_phases<0 || p_phases>VS::MAX_PARTICLE_COLOR_PHASES ); + particles->data.color_phase_count=p_phases; + +} +int Rasterizer3DS::particles_get_color_phases(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.color_phase_count; +} + + +void Rasterizer3DS::particles_set_color_phase_pos(RID p_particles, int p_phase, float p_pos) { + + ERR_FAIL_INDEX(p_phase, VS::MAX_PARTICLE_COLOR_PHASES); + if (p_pos<0.0) + p_pos=0.0; + if (p_pos>1.0) + p_pos=1.0; + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.color_phases[p_phase].pos=p_pos; + +} +float Rasterizer3DS::particles_get_color_phase_pos(RID p_particles, int p_phase) const { + + ERR_FAIL_INDEX_V(p_phase, VS::MAX_PARTICLE_COLOR_PHASES, -1.0); + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.color_phases[p_phase].pos; + +} + +void Rasterizer3DS::particles_set_color_phase_color(RID p_particles, int p_phase, const Color& p_color) { + + ERR_FAIL_INDEX(p_phase, VS::MAX_PARTICLE_COLOR_PHASES); + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.color_phases[p_phase].color=p_color; + + //update alpha + particles->has_alpha=false; + for(int i=0;idata.color_phases[i].color.a<0.99) + particles->has_alpha=true; + } + +} + +Color Rasterizer3DS::particles_get_color_phase_color(RID p_particles, int p_phase) const { + + ERR_FAIL_INDEX_V(p_phase, VS::MAX_PARTICLE_COLOR_PHASES, Color()); + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,Color()); + return particles->data.color_phases[p_phase].color; + +} + +void Rasterizer3DS::particles_set_attractors(RID p_particles, int p_attractors) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + ERR_FAIL_COND( p_attractors<0 || p_attractors>VisualServer::MAX_PARTICLE_ATTRACTORS ); + particles->data.attractor_count=p_attractors; + +} +int Rasterizer3DS::particles_get_attractors(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.attractor_count; +} + +void Rasterizer3DS::particles_set_attractor_pos(RID p_particles, int p_attractor, const Vector3& p_pos) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + ERR_FAIL_INDEX(p_attractor,particles->data.attractor_count); + particles->data.attractors[p_attractor].pos=p_pos;; +} +Vector3 Rasterizer3DS::particles_get_attractor_pos(RID p_particles,int p_attractor) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,Vector3()); + ERR_FAIL_INDEX_V(p_attractor,particles->data.attractor_count,Vector3()); + return particles->data.attractors[p_attractor].pos; +} + +void Rasterizer3DS::particles_set_attractor_strength(RID p_particles, int p_attractor, float p_force) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + ERR_FAIL_INDEX(p_attractor,particles->data.attractor_count); + particles->data.attractors[p_attractor].force=p_force; +} + +float Rasterizer3DS::particles_get_attractor_strength(RID p_particles,int p_attractor) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,0); + ERR_FAIL_INDEX_V(p_attractor,particles->data.attractor_count,0); + return particles->data.attractors[p_attractor].force; +} + +void Rasterizer3DS::particles_set_material(RID p_particles, RID p_material,bool p_owned) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + if (particles->material_owned && particles->material.is_valid()) + free(particles->material); + + particles->material_owned=p_owned; + + particles->material=p_material; + +} +RID Rasterizer3DS::particles_get_material(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,RID()); + return particles->material; + +} + +void Rasterizer3DS::particles_set_use_local_coordinates(RID p_particles, bool p_enable) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.local_coordinates=p_enable; + +} + +bool Rasterizer3DS::particles_is_using_local_coordinates(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,false); + return particles->data.local_coordinates; +} +bool Rasterizer3DS::particles_has_height_from_velocity(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,false); + return particles->data.height_from_velocity; +} + +void Rasterizer3DS::particles_set_height_from_velocity(RID p_particles, bool p_enable) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.height_from_velocity=p_enable; + +} + +AABB Rasterizer3DS::particles_get_aabb(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,AABB()); + return particles->data.visibility_aabb; +} + +/* SKELETON API */ + +RID Rasterizer3DS::skeleton_create() { + + Skeleton *skeleton = memnew( Skeleton ); + ERR_FAIL_COND_V(!skeleton,RID()); + return skeleton_owner.make_rid( skeleton ); +} +void Rasterizer3DS::skeleton_resize(RID p_skeleton,int p_bones) { + + Skeleton *skeleton = skeleton_owner.get( p_skeleton ); + ERR_FAIL_COND(!skeleton); + if (p_bones == skeleton->bones.size()) { + return; + }; + + skeleton->bones.resize(p_bones); + +} +int Rasterizer3DS::skeleton_get_bone_count(RID p_skeleton) const { + + Skeleton *skeleton = skeleton_owner.get( p_skeleton ); + ERR_FAIL_COND_V(!skeleton, -1); + return skeleton->bones.size(); +} +void Rasterizer3DS::skeleton_bone_set_transform(RID p_skeleton,int p_bone, const Transform& p_transform) { + + Skeleton *skeleton = skeleton_owner.get( p_skeleton ); + ERR_FAIL_COND(!skeleton); + ERR_FAIL_INDEX( p_bone, skeleton->bones.size() ); + + skeleton->bones[p_bone] = p_transform; +} + +Transform Rasterizer3DS::skeleton_bone_get_transform(RID p_skeleton,int p_bone) { + + Skeleton *skeleton = skeleton_owner.get( p_skeleton ); + ERR_FAIL_COND_V(!skeleton, Transform()); + ERR_FAIL_INDEX_V( p_bone, skeleton->bones.size(), Transform() ); + + // something + return skeleton->bones[p_bone]; +} + + +/* LIGHT API */ + +RID Rasterizer3DS::light_create(VS::LightType p_type) { + + Light *light = memnew( Light ); + light->type=p_type; + return light_owner.make_rid(light); +} + +VS::LightType Rasterizer3DS::light_get_type(RID p_light) const { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND_V(!light,VS::LIGHT_OMNI); + return light->type; +} + +void Rasterizer3DS::light_set_color(RID p_light,VS::LightColor p_type, const Color& p_color) { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND(!light); + ERR_FAIL_INDEX( p_type, 3 ); + light->colors[p_type]=p_color; +} +Color Rasterizer3DS::light_get_color(RID p_light,VS::LightColor p_type) const { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND_V(!light, Color()); + ERR_FAIL_INDEX_V( p_type, 3, Color() ); + return light->colors[p_type]; +} + +void Rasterizer3DS::light_set_shadow(RID p_light,bool p_enabled) { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND(!light); + light->shadow_enabled=p_enabled; +} + +bool Rasterizer3DS::light_has_shadow(RID p_light) const { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND_V(!light,false); + return light->shadow_enabled; +} + +void Rasterizer3DS::light_set_volumetric(RID p_light,bool p_enabled) { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND(!light); + light->volumetric_enabled=p_enabled; + +} +bool Rasterizer3DS::light_is_volumetric(RID p_light) const { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND_V(!light,false); + return light->volumetric_enabled; +} + +void Rasterizer3DS::light_set_projector(RID p_light,RID p_texture) { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND(!light); + light->projector=p_texture; +} +RID Rasterizer3DS::light_get_projector(RID p_light) const { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND_V(!light,RID()); + return light->projector; +} + +void Rasterizer3DS::light_set_var(RID p_light, VS::LightParam p_var, float p_value) { + + Light * light = light_owner.get( p_light ); + ERR_FAIL_COND(!light); + ERR_FAIL_INDEX( p_var, VS::LIGHT_PARAM_MAX ); + + light->vars[p_var]=p_value; +} +float Rasterizer3DS::light_get_var(RID p_light, VS::LightParam p_var) const { + + Light * light = light_owner.get( p_light ); + ERR_FAIL_COND_V(!light,0); + + ERR_FAIL_INDEX_V( p_var, VS::LIGHT_PARAM_MAX,0 ); + + return light->vars[p_var]; +} + +void Rasterizer3DS::light_set_operator(RID p_light,VS::LightOp p_op) { + + Light * light = light_owner.get( p_light ); + ERR_FAIL_COND(!light); + + +}; + +VS::LightOp Rasterizer3DS::light_get_operator(RID p_light) const { + + return VS::LightOp(0); +}; + +void Rasterizer3DS::light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode) { + + +} + +VS::LightOmniShadowMode Rasterizer3DS::light_omni_get_shadow_mode(RID p_light) const{ + + return VS::LightOmniShadowMode(0); +} + +void Rasterizer3DS::light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode) { + + +} + +VS::LightDirectionalShadowMode Rasterizer3DS::light_directional_get_shadow_mode(RID p_light) const { + + return VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; +} + +void Rasterizer3DS::light_directional_set_shadow_param(RID p_light,VS::LightDirectionalShadowParam p_param, float p_value) { + + +} + +float Rasterizer3DS::light_directional_get_shadow_param(RID p_light,VS::LightDirectionalShadowParam p_param) const { + + return 0; +} + + +AABB Rasterizer3DS::light_get_aabb(RID p_light) const { + + Light *light = light_owner.get( p_light ); + ERR_FAIL_COND_V(!light,AABB()); + + switch( light->type ) { + + case VS::LIGHT_SPOT: { + + float len=light->vars[VS::LIGHT_PARAM_RADIUS]; + float size=Math::tan(Math::deg2rad(light->vars[VS::LIGHT_PARAM_SPOT_ANGLE]))*len; + return AABB( Vector3( -size,-size,-len ), Vector3( size*2, size*2, len ) ); + } break; + case VS::LIGHT_OMNI: { + + float r = light->vars[VS::LIGHT_PARAM_RADIUS]; + return AABB( -Vector3(r,r,r), Vector3(r,r,r)*2 ); + } break; + case VS::LIGHT_DIRECTIONAL: { + + return AABB(); + } break; + default: {} + } + + ERR_FAIL_V( AABB() ); +} + + +RID Rasterizer3DS::light_instance_create(RID p_light) { + + Light *light = light_owner.get( p_light ); + ERR_FAIL_COND_V(!light, RID()); + + LightInstance *light_instance = memnew( LightInstance ); + + light_instance->light=p_light; + light_instance->base=light; + + + return light_instance_owner.make_rid( light_instance ); +} +void Rasterizer3DS::light_instance_set_transform(RID p_light_instance,const Transform& p_transform) { + + LightInstance *lighti = light_instance_owner.get( p_light_instance ); + ERR_FAIL_COND(!lighti); + lighti->transform=p_transform; + +} + +bool Rasterizer3DS::light_instance_has_shadow(RID p_light_instance) const { + + return false; + +} + + +bool Rasterizer3DS::light_instance_assign_shadow(RID p_light_instance) { + + return false; + +} + + +Rasterizer::ShadowType Rasterizer3DS::light_instance_get_shadow_type(RID p_light_instance) const { + + LightInstance *lighti = light_instance_owner.get( p_light_instance ); + ERR_FAIL_COND_V(!lighti,Rasterizer::SHADOW_NONE); + + switch(lighti->base->type) { + + case VS::LIGHT_DIRECTIONAL: return SHADOW_PSM; break; + case VS::LIGHT_OMNI: return SHADOW_DUAL_PARABOLOID; break; + case VS::LIGHT_SPOT: return SHADOW_SIMPLE; break; + } + + return Rasterizer::SHADOW_NONE; +} + +Rasterizer::ShadowType Rasterizer3DS::light_instance_get_shadow_type(RID p_light_instance,bool p_far) const { + + return SHADOW_NONE; +} +void Rasterizer3DS::light_instance_set_shadow_transform(RID p_light_instance, int p_index, const CameraMatrix& p_camera, const Transform& p_transform, float p_split_near,float p_split_far) { + + +} + +int Rasterizer3DS::light_instance_get_shadow_passes(RID p_light_instance) const { + + return 0; +} + +bool Rasterizer3DS::light_instance_get_pssm_shadow_overlap(RID p_light_instance) const { + + return false; +} + + +void Rasterizer3DS::light_instance_set_custom_transform(RID p_light_instance, int p_index, const CameraMatrix& p_camera, const Transform& p_transform, float p_split_near,float p_split_far) { + + LightInstance *lighti = light_instance_owner.get( p_light_instance ); + ERR_FAIL_COND(!lighti); + + ERR_FAIL_COND(lighti->base->type!=VS::LIGHT_DIRECTIONAL); + ERR_FAIL_INDEX(p_index,1); + + lighti->custom_projection=p_camera; + lighti->custom_transform=p_transform; + +} +void Rasterizer3DS::shadow_clear_near() { + + +} + +bool Rasterizer3DS::shadow_allocate_near(RID p_light) { + + return false; +} + +bool Rasterizer3DS::shadow_allocate_far(RID p_light) { + + return false; +} + +/* PARTICLES INSTANCE */ + +RID Rasterizer3DS::particles_instance_create(RID p_particles) { + + ERR_FAIL_COND_V(!particles_owner.owns(p_particles),RID()); + ParticlesInstance *particles_instance = memnew( ParticlesInstance ); + ERR_FAIL_COND_V(!particles_instance, RID() ); + particles_instance->particles=p_particles; + return particles_instance_owner.make_rid(particles_instance); +} + +void Rasterizer3DS::particles_instance_set_transform(RID p_particles_instance,const Transform& p_transform) { + + ParticlesInstance *particles_instance=particles_instance_owner.get(p_particles_instance); + ERR_FAIL_COND(!particles_instance); + particles_instance->transform=p_transform; +} + + +/* RENDER API */ +/* all calls (inside begin/end shadow) are always warranted to be in the following order: */ + + +RID Rasterizer3DS::viewport_data_create() { + + return RID(); +} + +RID Rasterizer3DS::render_target_create(){ + + return RID(); + +} +void Rasterizer3DS::render_target_set_size(RID p_render_target, int p_width, int p_height){ + + +} +RID Rasterizer3DS::render_target_get_texture(RID p_render_target) const{ + + return RID(); + +} +bool Rasterizer3DS::render_target_renedered_in_frame(RID p_render_target){ + + return false; +} + + +void Rasterizer3DS::begin_frame() { + C3D_FrameBegin(C3D_FRAME_SYNCDRAW); + C3D_RenderTargetClear(top_rt->target, C3D_CLEAR_ALL, clear_color_top, 0); + C3D_FrameDrawOn(top_rt->target); +} + +void Rasterizer3DS::capture_viewport(Image* r_capture) { + + +} + + +void Rasterizer3DS::clear_viewport(const Color& p_color) { + + clear_color_top = convert_color(&p_color); + // begin_frame(); +}; + +void Rasterizer3DS::set_viewport(const VS::ViewportRect& p_viewport) { + + + +} + +void Rasterizer3DS::set_render_target(RID p_render_target, bool p_transparent_bg, bool p_vflip) { + + +} + + +void Rasterizer3DS::begin_scene(RID p_viewport_data,RID p_env,VS::ScenarioDebugMode p_debug) { + /* + C3D_TexEnv* env = C3D_GetTexEnv(0); + C3D_TexEnvSrc(env, C3D_Both, GPU_FRAGMENT_PRIMARY_COLOR, GPU_FRAGMENT_SECONDARY_COLOR, (GPU_TEVSRC)0); + // C3D_TexEnvOp(env, C3D_Both, 0, 0, 0); + C3D_TexEnvFunc(env, C3D_Both, GPU_ADD); + + C3D_TexBind(0, NULL);*/ + + // C3D_BindProgram(&program); + // _set_uniform(uLoc_modelView, Matrix32()); +}; + +void Rasterizer3DS::begin_shadow_map( RID p_light_instance, int p_shadow_pass ) { + +} + +void Rasterizer3DS::set_camera(const Transform& p_world,const CameraMatrix& p_projection) { + + // _set_uniform(uLoc_projection, p_projection); +} + +void Rasterizer3DS::add_light( RID p_light_instance ) { + + + +} + + + + +void Rasterizer3DS::add_mesh( const RID& p_mesh, const InstanceData *p_data) { + + +} + +void Rasterizer3DS::add_multimesh( const RID& p_multimesh, const InstanceData *p_data){ + + + + +} + +void Rasterizer3DS::add_particles( const RID& p_particle_instance, const InstanceData *p_data){ + + + +} + + + +void Rasterizer3DS::end_scene() { + // C3D_Flush(); + +} +void Rasterizer3DS::end_shadow_map() { + +} + + +void Rasterizer3DS::end_frame() { + + C3D_FrameEnd(0); + // C3D_FrameBufTransfer(&top_rt->target->frameBuf, top_rt->target->screen, top_rt->target->side, top_rt->target->transferFlags); + // gfxSwapBuffersGpu(); +} + +/* CANVAS API */ + + +void Rasterizer3DS::canvas_begin() { + // C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projection); + + + + // Mtx_OrthoTilt(&projection, 0.0, 400.0, 240.0, 0.0, 0.0, 1.0, true); + + // C3D_BindProgram(&program); + + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projection); + // drawSpriteImmediate(0, 0, 0, 32, 32); + /* + C3D_ImmDrawBegin(GPU_TRIANGLES); + C3D_ImmSendAttrib(200.0f, 200.0f, 0.5f, 0.0f); // v0=position + C3D_ImmSendAttrib(1.0f, 0.0f, 0.0f, 1.0f); // v1=color + + C3D_ImmSendAttrib(100.0f, 40.0f, 0.5f, 0.0f); + C3D_ImmSendAttrib(1.0f, 1.0f, 0.0f, 1.0f); + + C3D_ImmSendAttrib(300.0f, 40.0f, 0.5f, 0.0f); + C3D_ImmSendAttrib(0.0f, 0.0f, 1.0f, 1.0f); + C3D_ImmDrawEnd();*/ +} +void Rasterizer3DS::canvas_disable_blending() { + + + +} + +void Rasterizer3DS::canvas_set_opacity(float p_opacity) { + + +} + +void Rasterizer3DS::canvas_set_blend_mode(VS::MaterialBlendMode p_mode) { + + +} + + +void Rasterizer3DS::canvas_begin_rect(const Matrix32& p_transform) { + // _set_uniform(uLoc_modelView, p_transform); +} + +void Rasterizer3DS::canvas_set_clip(bool p_clip, const Rect2& p_rect) { + + + + +} + +void Rasterizer3DS::canvas_end_rect() { + + +} + +void Rasterizer3DS::canvas_draw_line(const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width) { + + + +} + +void Rasterizer3DS::canvas_draw_rect(const Rect2& p_rect, int p_flags, const Rect2& p_source,RID p_texture,const Color& p_modulate) { + + + // _set_glcoloro( p_modulate,canvas_opacity ); + + if ( p_texture.is_valid() ) { + + // sceGuEnable(GU_TEXTURE_2D); + Texture *texture = texture_owner.get( p_texture ); + ERR_FAIL_COND(!texture); + // glActiveTexture(GL_TEXTURE0); + // glBindTexture( GL_TEXTURE_2D,texture->tex_id ); +/* + C3D_TexEnv* env = C3D_GetTexEnv(0); + C3D_TexEnvSrc(env, C3D_Both, GPU_FRAGMENT_PRIMARY_COLOR, GPU_FRAGMENT_SECONDARY_COLOR); + C3D_TexEnvOpRgb(env, GPU_TEVOP_RGB_SRC_COLOR); + C3D_TexEnvOpAlpha(env,GPU_TEVOP_A_SRC_ALPHA); + C3D_TexEnvFunc(env, C3D_Both, GPU_ADD); + + C3D_TexBind(0, &texture->texture);*/ + + if (!(p_flags&CANVAS_RECT_REGION)) { + + Rect2 region = Rect2(0,0,texture->width,texture->height); + _draw_textured_quad(p_rect,region,region.size,p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V); + + } else { + + + _draw_textured_quad(p_rect, p_source, Size2(texture->width,texture->height),p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V ); + + } + + } else { + + WARN_PRINT("p_texture is not valid"); + + // sceGuDisable(GU_TEXTURE_2D); + // _draw_quad( p_rect ); + + } + +} +void Rasterizer3DS::canvas_draw_style_box(const Rect2& p_rect, RID p_texture,const float *p_margin, bool p_draw_center,const Color& p_modulate) { + + +} +void Rasterizer3DS::canvas_draw_primitive(const Vector& p_points, const Vector& p_colors,const Vector& p_uvs, RID p_texture,float p_width) { + + + +} + + +void Rasterizer3DS::canvas_draw_polygon(int p_vertex_count, const int* p_indices, const Vector2* p_vertices, const Vector2* p_uvs, const Color* p_colors,const RID& p_texture,bool p_singlecolor) { + + + +} + +void Rasterizer3DS::canvas_set_transform(const Matrix32& p_transform) { + + +} + +/* ENVIRONMENT */ + +RID Rasterizer3DS::environment_create() { + + Environment * env = memnew( Environment ); + return environment_owner.make_rid(env); +} + +void Rasterizer3DS::environment_set_background(RID p_env,VS::EnvironmentBG p_bg) { + + ERR_FAIL_INDEX(p_bg,VS::ENV_BG_MAX); + Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND(!env); + env->bg_mode=p_bg; +} + +VS::EnvironmentBG Rasterizer3DS::environment_get_background(RID p_env) const{ + + const Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND_V(!env,VS::ENV_BG_MAX); + return env->bg_mode; +} + +void Rasterizer3DS::environment_set_background_param(RID p_env,VS::EnvironmentBGParam p_param, const Variant& p_value){ + + ERR_FAIL_INDEX(p_param,VS::ENV_BG_PARAM_MAX); + Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND(!env); + env->bg_param[p_param]=p_value; + +} +Variant Rasterizer3DS::environment_get_background_param(RID p_env,VS::EnvironmentBGParam p_param) const{ + + ERR_FAIL_INDEX_V(p_param,VS::ENV_BG_PARAM_MAX,Variant()); + const Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND_V(!env,Variant()); + return env->bg_param[p_param]; + +} + +void Rasterizer3DS::environment_set_enable_fx(RID p_env,VS::EnvironmentFx p_effect,bool p_enabled){ + + ERR_FAIL_INDEX(p_effect,VS::ENV_FX_MAX); + Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND(!env); + env->fx_enabled[p_effect]=p_enabled; +} +bool Rasterizer3DS::environment_is_fx_enabled(RID p_env,VS::EnvironmentFx p_effect) const{ + + ERR_FAIL_INDEX_V(p_effect,VS::ENV_FX_MAX,false); + const Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND_V(!env,false); + return env->fx_enabled[p_effect]; + +} + +void Rasterizer3DS::environment_fx_set_param(RID p_env,VS::EnvironmentFxParam p_param,const Variant& p_value){ + + ERR_FAIL_INDEX(p_param,VS::ENV_FX_PARAM_MAX); + Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND(!env); + env->fx_param[p_param]=p_value; +} +Variant Rasterizer3DS::environment_fx_get_param(RID p_env,VS::EnvironmentFxParam p_param) const{ + + ERR_FAIL_INDEX_V(p_param,VS::ENV_FX_PARAM_MAX,Variant()); + const Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND_V(!env,Variant()); + return env->fx_param[p_param]; + +} + + +RID Rasterizer3DS::sampled_light_dp_create(int p_width,int p_height) { + + return sampled_light_owner.make_rid(memnew(SampledLight)); +} + +void Rasterizer3DS::sampled_light_dp_update(RID p_sampled_light, const Color *p_data, float p_multiplier) { + + +} + + +/*MISC*/ + +bool Rasterizer3DS::is_texture(const RID& p_rid) const { + + return texture_owner.owns(p_rid); +} +bool Rasterizer3DS::is_material(const RID& p_rid) const { + + return material_owner.owns(p_rid); +} +bool Rasterizer3DS::is_mesh(const RID& p_rid) const { + + return mesh_owner.owns(p_rid); +} + +bool Rasterizer3DS::is_immediate(const RID& p_rid) const { + + return immediate_owner.owns(p_rid); +} + +bool Rasterizer3DS::is_multimesh(const RID& p_rid) const { + + return multimesh_owner.owns(p_rid); +} +bool Rasterizer3DS::is_particles(const RID &p_beam) const { + + return particles_owner.owns(p_beam); +} + +bool Rasterizer3DS::is_light(const RID& p_rid) const { + + return light_owner.owns(p_rid); +} +bool Rasterizer3DS::is_light_instance(const RID& p_rid) const { + + return light_instance_owner.owns(p_rid); +} +bool Rasterizer3DS::is_particles_instance(const RID& p_rid) const { + + return particles_instance_owner.owns(p_rid); +} +bool Rasterizer3DS::is_skeleton(const RID& p_rid) const { + + return skeleton_owner.owns(p_rid); +} +bool Rasterizer3DS::is_environment(const RID& p_rid) const { + + return environment_owner.owns(p_rid); +} + +bool Rasterizer3DS::is_shader(const RID& p_rid) const { + + return false; +} + +void Rasterizer3DS::free(const RID& p_rid) { + + if (texture_owner.owns(p_rid)) { + + // delete the texture + Texture *texture = texture_owner.get(p_rid); + texture_owner.free(p_rid); + memdelete(texture); + + } else if (shader_owner.owns(p_rid)) { + + // delete the texture + Shader *shader = shader_owner.get(p_rid); + shader_owner.free(p_rid); + memdelete(shader); + + } else if (material_owner.owns(p_rid)) { + + Material *material = material_owner.get( p_rid ); + material_owner.free(p_rid); + memdelete(material); + + } else if (mesh_owner.owns(p_rid)) { + + Mesh *mesh = mesh_owner.get(p_rid); + + for (int i=0;isurfaces.size();i++) { + + memdelete( mesh->surfaces[i] ); + }; + + mesh->surfaces.clear(); + mesh_owner.free(p_rid); + memdelete(mesh); + + } else if (multimesh_owner.owns(p_rid)) { + + MultiMesh *multimesh = multimesh_owner.get(p_rid); + multimesh_owner.free(p_rid); + memdelete(multimesh); + + } else if (immediate_owner.owns(p_rid)) { + + Immediate *immediate = immediate_owner.get(p_rid); + immediate_owner.free(p_rid); + memdelete(immediate); + + } else if (particles_owner.owns(p_rid)) { + + Particles *particles = particles_owner.get(p_rid); + particles_owner.free(p_rid); + memdelete(particles); + } else if (particles_instance_owner.owns(p_rid)) { + + ParticlesInstance *particles_isntance = particles_instance_owner.get(p_rid); + particles_instance_owner.free(p_rid); + memdelete(particles_isntance); + + } else if (skeleton_owner.owns(p_rid)) { + + Skeleton *skeleton = skeleton_owner.get( p_rid ); + skeleton_owner.free(p_rid); + memdelete(skeleton); + + } else if (light_owner.owns(p_rid)) { + + Light *light = light_owner.get( p_rid ); + light_owner.free(p_rid); + memdelete(light); + + } else if (light_instance_owner.owns(p_rid)) { + + LightInstance *light_instance = light_instance_owner.get( p_rid ); + light_instance_owner.free(p_rid); + memdelete( light_instance ); + + + } else if (environment_owner.owns(p_rid)) { + + Environment *env = environment_owner.get( p_rid ); + environment_owner.free(p_rid); + memdelete( env ); + } else if (sampled_light_owner.owns(p_rid)) { + + SampledLight *sampled_light = sampled_light_owner.get( p_rid ); + ERR_FAIL_COND(!sampled_light); + + sampled_light_owner.free(p_rid); + memdelete( sampled_light ); + + }; +} + + +void Rasterizer3DS::custom_shade_model_set_shader(int p_model, RID p_shader) { + + +}; + +RID Rasterizer3DS::custom_shade_model_get_shader(int p_model) const { + + return RID(); +}; + +void Rasterizer3DS::custom_shade_model_set_name(int p_model, const String& p_name) { + +}; + +String Rasterizer3DS::custom_shade_model_get_name(int p_model) const { + + return String(); +}; + +void Rasterizer3DS::custom_shade_model_set_param_info(int p_model, const List& p_info) { + +}; + +void Rasterizer3DS::custom_shade_model_get_param_info(int p_model, List* p_info) const { + +}; + + + +void Rasterizer3DS::init() { + C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); + + top_rt = memnew(RenderTarget); + + top_rt->target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); + C3D_RenderTargetSetOutput(top_rt->target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); + + + simple_2ds = DVLB_ParseFile((u32*)shader_builtin_simple_2d, sizeof(shader_builtin_simple_2d)); + shaderProgramInit(&program); + shaderProgramSetVsh(&program, &simple_2ds->DVLE[0]); + C3D_BindProgram(&program); + + uLoc_projection = shaderInstanceGetUniformLocation(program.vertexShader, "projection"); + // uLoc_modelView = shaderInstanceGetUniformLocation(program.vertexShader, "modelView"); + + // Configure attributes for use with the vertex shader + C3D_AttrInfo* attrInfo = C3D_GetAttrInfo(); + AttrInfo_Init(attrInfo); + AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position + // AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2); // v1=color + AttrInfo_AddFixed(attrInfo, 1); + + // Mtx_PerspTilt(&projection, C3D_AngleFromDegrees(80.0f), C3D_AspectRatioTop, 0.01f, 1000.0f, false); + Mtx_OrthoTilt(&projection, 0.0, 400.0, 0.0, 240.0, 0.0, 1.0, true); + /* + C3D_TexEnv* env = C3D_GetTexEnv(0); + C3D_TexEnvInit(env); + C3D_TexEnvSrc(env, C3D_Both, GPU_PRIMARY_COLOR, (GPU_TEVSRC)0, (GPU_TEVSRC)0); + C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE);*/ + + C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + C3D_DepthTest(true, GPU_GEQUAL, GPU_WRITE_ALL); + // Mtx_OrthoTilt(&projection, 0.0, 400.0, 0.0, 240.0, 0.0, 1.0, true); + + + void* vbo_data = linearAlloc(sizeof(vertex_list)); + memcpy(vbo_data, vertex_list, sizeof(vertex_list)); + + // Configure buffers + C3D_BufInfo* bufInfo = C3D_GetBufInfo(); + BufInfo_Init(bufInfo); + BufInfo_Add(bufInfo, vbo_data, sizeof(vertex3ds), 1, 0x0); + + C3D_FixedAttribSet(1, 1.0, 1.0, 1.0, 1.0); + printf("Rasterizer::Init OK!\n"); +} + +void Rasterizer3DS::finish() { + + +} + +int Rasterizer3DS::get_render_info(VS::RenderInfo p_info) { + + return 0; +} + +bool Rasterizer3DS::needs_to_draw_next_frame() const { + + return false; +} + + +bool Rasterizer3DS::has_feature(VS::Features p_feature) const { + + return false; + +} + + +Rasterizer3DS::Rasterizer3DS() { + +}; + +Rasterizer3DS::~Rasterizer3DS() { + shaderProgramFree(&program); + DVLB_Free(simple_2ds); + C3D_Fini(); +}; + diff --git a/platform/3ds/rasterizer_3ds Kopie.cpp b/platform/3ds/rasterizer_3ds Kopie.cpp new file mode 100644 index 00000000..c6d92e1e --- /dev/null +++ b/platform/3ds/rasterizer_3ds Kopie.cpp @@ -0,0 +1,2268 @@ +/*************************************************************************/ +/* rasterizer_3ds.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 "rasterizer_3ds.h" +#include "shaders/simple_3d.h" +#include "shaders/simple_2d.h" + +static const vertex3ds vertex_list[] = +{ + { 200.0f, 200.0f, 0.5f }, + { 100.0f, 40.0f, 0.5f }, + { 300.0f, 40.0f, 0.5f }, +}; + +#define vertex_list_count (sizeof(vertex_list)/sizeof(vertex_list[0])) + +#define DISPLAY_TRANSFER_FLAGS \ + (GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | GX_TRANSFER_RAW_COPY(0) | \ + GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | \ + GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO)) + + +#define TEXTURE_TRANSFER_FLAGS (GX_TRANSFER_FLIP_VERT(1) | GX_TRANSFER_OUT_TILED(1) | GX_TRANSFER_RAW_COPY(0) | GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | \ + GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO)) + + +void _set_uniform(int uniform_location, const Matrix32& p_transform) +{ + const Matrix32& tr = p_transform; + + C3D_Mtx mtx; + + float matrix[16] = { /* build a 16x16 matrix */ + tr.elements[2][0], 0, tr.elements[1][0], tr.elements[0][0], + tr.elements[2][1], 0, tr.elements[1][1], tr.elements[0][1], + 0, 1, 0, 0, + 1, 0, 0, 0, + }; + + memcpy(mtx.m, matrix, sizeof(matrix)); + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uniform_location, &mtx); +} + +void _set_uniform(int uniform_location, const CameraMatrix& p_matrix) +{ + // Swap X/Y axis due to 3DS screens being sideways + // and adjust clipping range from [-1, 1] to [-1, 0] + float m[16] = { + 0, -1, 0, 0, + 1, 0, 0, 0, + 0, 0, 0.5, 0, + 0, 0, -0.5, 1, + }; + + CameraMatrix p = *reinterpret_cast(m) * p_matrix; + + C3D_Mtx mtx; + float *to = mtx.m; + const float *from = reinterpret_cast(p.matrix); + + + to[0] = from[12]; + to[1] = from[8]; + to[2] = from[4]; + to[3] = from[0]; + to[4] = from[13]; + to[5] = from[9]; + to[6] = from[5]; + to[7] = from[1]; + to[8] = from[14]; + to[9] = from[10]; + to[10] = from[6]; + to[11] = from[2]; + to[12] = from[15]; + to[13] = from[11]; + to[14] = from[7]; + to[15] = from[3]; + + + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uniform_location, &mtx); +} + +/* TEXTURE API */ + + +RID Rasterizer3DS::texture_create() { + + Texture *texture = memnew(Texture); + ERR_FAIL_COND_V(!texture,RID()); + return texture_owner.make_rid( texture ); + +} + +void Rasterizer3DS::texture_allocate(RID p_texture,int p_width, int p_height,Image::Format p_format,uint32_t p_flags) { + + + Texture *texture = texture_owner.get( p_texture ); + ERR_FAIL_COND(!texture); + C3D_TexInit(&texture->texture, p_width, p_height, GPU_RGBA8); + texture->width=p_width; + texture->height=p_height; + texture->format=p_format; + texture->flags=p_flags; +} + +void Rasterizer3DS::texture_set_data(RID p_texture,const Image& p_image,VS::CubeMapSide p_cube_side) { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND(!texture); + ERR_FAIL_COND(texture->format != p_image.get_format() ); + + texture->image[p_cube_side]=p_image; + + DVector d = p_image.get_data(); + const u32* buffer = reinterpret_cast(d.read().ptr()); + u8 * gpuBuffer = (u8 *)linearAlloc(texture->width * texture->height * 4); + + u32 * src = (u32 *)buffer; + u32 * dst = (u32 *)gpuBuffer; + + for (unsigned y = 0; y < texture->height; y++) + { + for (unsigned x = 0; x < texture->width; x++) + { + u32 clr = *src; + // *dst = __builtin_bswap32(clr); + *dst = 0x0; + } + dst += 4; + } + + GSPGPU_FlushDataCache((u32 *)gpuBuffer, texture->width * texture->height * 4); + + C3D_SyncDisplayTransfer((u32 *)gpuBuffer, GX_BUFFER_DIM(texture->width, texture->height), (u32 *)texture->texture.data, GX_BUFFER_DIM(texture->width, texture->height), TEXTURE_TRANSFER_FLAGS); + + // gspWaitForPPF(); + C3D_TexSetFilter(&texture->texture, GPU_LINEAR, GPU_NEAREST); + C3D_TexBind(0, &texture->texture); + + linearFree(gpuBuffer); + + C3D_TexEnv* env = C3D_GetTexEnv(0); + C3D_TexEnvInit(env); + C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, (GPU_TEVSRC)0, (GPU_TEVSRC)0); + C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE); + + +} + +Image Rasterizer3DS::texture_get_data(RID p_texture,VS::CubeMapSide p_cube_side) const { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,Image()); + + return texture->image[p_cube_side]; +} + +void Rasterizer3DS::texture_set_flags(RID p_texture,uint32_t p_flags) { + + Texture *texture = texture_owner.get( p_texture ); + ERR_FAIL_COND(!texture); + uint32_t cube = texture->flags & VS::TEXTURE_FLAG_CUBEMAP; + texture->flags=p_flags|cube; // can't remove a cube from being a cube + +} +uint32_t Rasterizer3DS::texture_get_flags(RID p_texture) const { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,0); + + return texture->flags; + +} +Image::Format Rasterizer3DS::texture_get_format(RID p_texture) const { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,Image::FORMAT_GRAYSCALE); + + return texture->format; +} +uint32_t Rasterizer3DS::texture_get_width(RID p_texture) const { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,0); + + return texture->width; +} +uint32_t Rasterizer3DS::texture_get_height(RID p_texture) const { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,0); + + return texture->height; +} + +bool Rasterizer3DS::texture_has_alpha(RID p_texture) const { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,0); + + return false; + +} + +void Rasterizer3DS::texture_set_size_override(RID p_texture,int p_width, int p_height) { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND(!texture); + + ERR_FAIL_COND(p_width<=0 || p_width>4096); + ERR_FAIL_COND(p_height<=0 || p_height>4096); + //real texture size is in alloc width and height +// texture->width=p_width; +// texture->height=p_height; + +} + +void Rasterizer3DS::texture_set_reload_hook(RID p_texture,ObjectID p_owner,const StringName& p_function) const { + + +} + +static void _draw_primitive(int p_points, const Vector3 *p_vertices, const Vector3 *p_normals, const Color* p_colors, const Vector3 *p_uvs,const Plane *p_tangents=NULL,int p_instanced=1) { + ERR_FAIL_COND(!p_vertices); + ERR_FAIL_COND(p_points <1 || p_points>4); + + // int type = prim_type[p_points - 1]; + + C3D_BufInfo* bufInfo = C3D_GetBufInfo(); + BufInfo_Init(bufInfo); + BufInfo_Add(bufInfo, p_vertices, sizeof(Vector3), 2, 0x10); + + C3D_DrawArrays(GPU_TRIANGLE_FAN, 0, 4); +}; +//--------------------------------------------------------------------------------- +static void drawSpriteImmediate( size_t idx, int x, int y, int width, int height ) { +//--------------------------------------------------------------------------------- + + float left = 0;//images[image].left; + float right = 0.5;//images[image].right; + float top = 0;//images[image].top; + float bottom = 0.5;//images[image].bottom; + + if (idx > 500) + return; + + // Draw a textured quad directly + C3D_ImmDrawBegin(GPU_TRIANGLE_STRIP); + C3D_ImmSendAttrib(x, y, 0.5f, 0.0f); // v0=position + C3D_ImmSendAttrib( left, top, 0.0f, 0.0f); + + C3D_ImmSendAttrib(x, y+height, 0.5f, 0.0f); + C3D_ImmSendAttrib( left, bottom, 0.0f, 0.0f); + + C3D_ImmSendAttrib(x+width, y, 0.5f, 0.0f); + C3D_ImmSendAttrib( right, top, 0.0f, 0.0f); + + C3D_ImmSendAttrib(x+width, y+height, 0.5f, 0.0f); + C3D_ImmSendAttrib( right, bottom, 0.0f, 0.0f); + C3D_ImmDrawEnd(); +} +void Rasterizer3DS::_draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_flip_h=false,bool p_flip_v=false ) { + VertexArray dscoords[4]= { + {Vector3( p_src_region.pos.x/p_tex_size.width, + p_src_region.pos.y/p_tex_size.height, 0), + Vector2( p_rect.pos.x, p_rect.pos.y )}, + + + {Vector3((p_src_region.pos.x+p_src_region.size.width)/p_tex_size.width, + p_src_region.pos.y/p_tex_size.height, 0), + Vector2( p_rect.pos.x+p_rect.size.width, p_rect.pos.y )}, + + {Vector3( (p_src_region.pos.x+p_src_region.size.width)/p_tex_size.width, + (p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height, 0), + Vector2( p_rect.pos.x+p_rect.size.width, p_rect.pos.y+p_rect.size.height )}, + + {Vector3( p_src_region.pos.x/p_tex_size.width, + (p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height, 0), + Vector2( p_rect.pos.x,p_rect.pos.y+p_rect.size.height )} + }; + + VertexArray dscoords23[4]= { + {Vector3( 0, + 0, 0), + Vector2( p_rect.pos.x, p_rect.pos.y )}, + + + {Vector3(5, + 0, 0), + Vector2( p_rect.pos.x+p_rect.size.width, p_rect.pos.y )}, + + {Vector3( 0, + 5, 0), + Vector2( p_rect.pos.x+p_rect.size.width, p_rect.pos.y+p_rect.size.height )}, + + {Vector3( 5, + 5, 0), + Vector2( p_rect.pos.x,p_rect.pos.y+p_rect.size.height )} + }; + + + if (p_flip_h) { + SWAP( dscoords[0], dscoords[1] ); + SWAP( dscoords[2], dscoords[3] ); + } + if (p_flip_v) { + SWAP( dscoords[1], dscoords[2] ); + SWAP( dscoords[0], dscoords[3] ); + } + + Vector3 coords[4]= { + + }; + + // void* vbo_data = linearAlloc(sizeof(dscoords)); + // memcpy(vbo_data, dscoords, sizeof(dscoords)); + // memcpy(vbo_data+sizeof(coords), texcoords, sizeof(texcoords)); + /* + C3D_AttrInfo* attrInfo = C3D_GetAttrInfo(); + AttrInfo_Init(attrInfo); + AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position + AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2); // v1=color + + C3D_BufInfo* bufInfo = C3D_GetBufInfo(); + BufInfo_Init(bufInfo); + BufInfo_Add(bufInfo, dscoords, sizeof(VertexArray), 2, 0x10); + + C3D_DrawArrays(GPU_TRIANGLE_STRIP, 0, sizeof(dscoords));*/ +/* + C3D_ImmDrawBegin(GPU_TRIANGLE_STRIP); + C3D_ImmSendAttrib(p_src_region.pos.x/p_tex_size.width, p_src_region.pos.y/p_tex_size.height, 0.5f, 0.0f); // v0=position + C3D_ImmSendAttrib(p_rect.pos.x, p_rect.pos.y, 0.0f, 0.0f); // v1=color + + C3D_ImmSendAttrib((p_src_region.pos.x+p_src_region.size.width)/p_tex_size.width, p_src_region.pos.y/p_tex_size.height, 0.5f, 0.0f); + C3D_ImmSendAttrib(p_rect.pos.x+p_rect.size.width, p_rect.pos.y, 0.0f, 0.0f); + + C3D_ImmSendAttrib((p_src_region.pos.x+p_src_region.size.width)/p_tex_size.width, (p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height, 0.5f, 0.0f); + C3D_ImmSendAttrib(p_rect.pos.x+p_rect.size.width, p_rect.pos.y+p_rect.size.height, 0.0f, 0.0f); + + C3D_ImmSendAttrib(p_src_region.pos.x/p_tex_size.width, (p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height, 0.5f, 0.0f); + C3D_ImmSendAttrib(p_rect.pos.x, p_rect.pos.y+p_rect.size.height, 0.0f, 0.0f); + + C3D_ImmDrawEnd();*/ + + // drawSpriteImmediate(0, 0, 0, 32, 32); + C3D_DrawArrays(GPU_TRIANGLES, 0, vertex_list_count); + + // Mtx_Identity(&modelView); + + // Mtx_Translate(&modelView, 0.0, 0.0, -2.5, true); + + // C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView); + + // Draw the triangle directly + + + // _draw_primitive(4,coords,0,0,texcoords); + + // linearFree(vbo_data); +} + +/* SHADER API */ + +/* SHADER API */ + +RID Rasterizer3DS::shader_create(VS::ShaderMode p_mode) { + + Shader *shader = memnew( Shader ); + shader->mode=p_mode; + shader->fragment_line=0; + shader->vertex_line=0; + shader->light_line=0; + RID rid = shader_owner.make_rid(shader); + + return rid; + +} + + + +void Rasterizer3DS::shader_set_mode(RID p_shader,VS::ShaderMode p_mode) { + + ERR_FAIL_INDEX(p_mode,3); + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND(!shader); + shader->mode=p_mode; + +} +VS::ShaderMode Rasterizer3DS::shader_get_mode(RID p_shader) const { + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND_V(!shader,VS::SHADER_MATERIAL); + return shader->mode; +} + +void Rasterizer3DS::shader_set_code(RID p_shader, const String& p_vertex, const String& p_fragment,const String& p_light,int p_vertex_ofs,int p_fragment_ofs,int p_light_ofs) { + + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND(!shader); + shader->fragment_code=p_fragment; + shader->vertex_code=p_vertex; + shader->light_code=p_light; + shader->fragment_line=p_fragment_ofs; + shader->vertex_line=p_vertex_ofs; + shader->light_line=p_vertex_ofs; + +} + + +String Rasterizer3DS::shader_get_vertex_code(RID p_shader) const { + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND_V(!shader,String()); + return shader->vertex_code; + +} + +String Rasterizer3DS::shader_get_fragment_code(RID p_shader) const { + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND_V(!shader,String()); + return shader->fragment_code; + +} + +String Rasterizer3DS::shader_get_light_code(RID p_shader) const { + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND_V(!shader,String()); + return shader->light_code; + +} + +void Rasterizer3DS::shader_get_param_list(RID p_shader, List *p_param_list) const { + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND(!shader); + +} + +/* COMMON MATERIAL API */ + + +RID Rasterizer3DS::material_create() { + + return material_owner.make_rid( memnew( Material ) ); +} + +void Rasterizer3DS::material_set_shader(RID p_material, RID p_shader) { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + material->shader=p_shader; + +} + +RID Rasterizer3DS::material_get_shader(RID p_material) const { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,RID()); + return material->shader; +} + +void Rasterizer3DS::material_set_param(RID p_material, const StringName& p_param, const Variant& p_value) { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + + if (p_value.get_type()==Variant::NIL) + material->shader_params.erase(p_param); + else + material->shader_params[p_param]=p_value; +} +Variant Rasterizer3DS::material_get_param(RID p_material, const StringName& p_param) const { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,Variant()); + + if (material->shader_params.has(p_param)) + return material->shader_params[p_param]; + else + return Variant(); +} + + +void Rasterizer3DS::material_set_flag(RID p_material, VS::MaterialFlag p_flag,bool p_enabled) { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + ERR_FAIL_INDEX(p_flag,VS::MATERIAL_FLAG_MAX); + material->flags[p_flag]=p_enabled; + +} +bool Rasterizer3DS::material_get_flag(RID p_material,VS::MaterialFlag p_flag) const { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,false); + ERR_FAIL_INDEX_V(p_flag,VS::MATERIAL_FLAG_MAX,false); + return material->flags[p_flag]; + + +} + +void Rasterizer3DS::material_set_depth_draw_mode(RID p_material, VS::MaterialDepthDrawMode p_mode) { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + material->depth_draw_mode=p_mode; +} + +VS::MaterialDepthDrawMode Rasterizer3DS::material_get_depth_draw_mode(RID p_material) const{ + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,VS::MATERIAL_DEPTH_DRAW_ALWAYS); + return material->depth_draw_mode; + +} + + +void Rasterizer3DS::material_set_blend_mode(RID p_material,VS::MaterialBlendMode p_mode) { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + material->blend_mode=p_mode; + +} +VS::MaterialBlendMode Rasterizer3DS::material_get_blend_mode(RID p_material) const { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,VS::MATERIAL_BLEND_MODE_ADD); + return material->blend_mode; +} + +void Rasterizer3DS::material_set_line_width(RID p_material,float p_line_width) { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + material->line_width=p_line_width; + +} +float Rasterizer3DS::material_get_line_width(RID p_material) const { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,0); + + return material->line_width; +} + +/* MESH API */ + + +RID Rasterizer3DS::mesh_create() { + + + return mesh_owner.make_rid( memnew( Mesh ) ); +} + + +void Rasterizer3DS::mesh_add_surface(RID p_mesh,VS::PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes,bool p_alpha_sort) { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + + ERR_FAIL_INDEX( p_primitive, VS::PRIMITIVE_MAX ); + ERR_FAIL_COND(p_arrays.size()!=VS::ARRAY_MAX); + + Surface s; + + + s.format=0; + + for(int i=0;imorph_target_count; + s.morph_format=s.format; + + + Surface *surface = memnew( Surface ); + *surface=s; + + mesh->surfaces.push_back(surface); + + +} + + + +void Rasterizer3DS::mesh_add_custom_surface(RID p_mesh,const Variant& p_dat) { + + ERR_EXPLAIN("Dummy Rasterizer does not support custom surfaces. Running on wrong platform?"); + ERR_FAIL_V(); +} + +Array Rasterizer3DS::mesh_get_surface_arrays(RID p_mesh,int p_surface) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,Array()); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Array() ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, Array() ); + + return surface->data; + + +} +Array Rasterizer3DS::mesh_get_surface_morph_arrays(RID p_mesh,int p_surface) const{ + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,Array()); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Array() ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, Array() ); + + return surface->morph_data; + +} + + +void Rasterizer3DS::mesh_set_morph_target_count(RID p_mesh,int p_amount) { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + ERR_FAIL_COND( mesh->surfaces.size()!=0 ); + + mesh->morph_target_count=p_amount; + +} + +int Rasterizer3DS::mesh_get_morph_target_count(RID p_mesh) const{ + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,-1); + + return mesh->morph_target_count; + +} + +void Rasterizer3DS::mesh_set_morph_target_mode(RID p_mesh,VS::MorphTargetMode p_mode) { + + ERR_FAIL_INDEX(p_mode,2); + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + + mesh->morph_target_mode=p_mode; + +} + +VS::MorphTargetMode Rasterizer3DS::mesh_get_morph_target_mode(RID p_mesh) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,VS::MORPH_MODE_NORMALIZED); + + return mesh->morph_target_mode; + +} + + + +void Rasterizer3DS::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material,bool p_owned) { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + ERR_FAIL_INDEX(p_surface, mesh->surfaces.size() ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND( !surface); + + if (surface->material_owned && surface->material.is_valid()) + free(surface->material); + + surface->material_owned=p_owned; + surface->material=p_material; +} + +RID Rasterizer3DS::mesh_surface_get_material(RID p_mesh, int p_surface) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,RID()); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), RID() ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, RID() ); + + return surface->material; +} + +int Rasterizer3DS::mesh_surface_get_array_len(RID p_mesh, int p_surface) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,-1); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), -1 ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, -1 ); + + Vector3Array arr = surface->data[VS::ARRAY_VERTEX]; + return arr.size(); + +} + +int Rasterizer3DS::mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,-1); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), -1 ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, -1 ); + + IntArray arr = surface->data[VS::ARRAY_INDEX]; + return arr.size(); + +} +uint32_t Rasterizer3DS::mesh_surface_get_format(RID p_mesh, int p_surface) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,0); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), 0 ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, 0 ); + + return surface->format; +} +VS::PrimitiveType Rasterizer3DS::mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,VS::PRIMITIVE_POINTS); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), VS::PRIMITIVE_POINTS ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, VS::PRIMITIVE_POINTS ); + + return surface->primitive; +} + +void Rasterizer3DS::mesh_remove_surface(RID p_mesh,int p_index) { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + ERR_FAIL_INDEX(p_index, mesh->surfaces.size() ); + Surface *surface = mesh->surfaces[p_index]; + ERR_FAIL_COND( !surface); + + memdelete( mesh->surfaces[p_index] ); + mesh->surfaces.remove(p_index); + +} +int Rasterizer3DS::mesh_get_surface_count(RID p_mesh) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,-1); + + return mesh->surfaces.size(); +} + +AABB Rasterizer3DS::mesh_get_aabb(RID p_mesh,RID p_skeleton) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,AABB()); + + AABB aabb; + + for (int i=0;isurfaces.size();i++) { + + if (i==0) + aabb=mesh->surfaces[i]->aabb; + else + aabb.merge_with(mesh->surfaces[i]->aabb); + } + + return aabb; +} + +void Rasterizer3DS::mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb) { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + + mesh->custom_aabb=p_aabb; +} + +AABB Rasterizer3DS::mesh_get_custom_aabb(RID p_mesh) const { + + const Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,AABB()); + + return mesh->custom_aabb; + +} + +/* MULTIMESH API */ + +RID Rasterizer3DS::multimesh_create() { + + return multimesh_owner.make_rid( memnew( MultiMesh )); +} + +void Rasterizer3DS::multimesh_set_instance_count(RID p_multimesh,int p_count) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh); + + multimesh->elements.clear(); // make sure to delete everything, so it "fails" in all implementations + multimesh->elements.resize(p_count); + +} +int Rasterizer3DS::multimesh_get_instance_count(RID p_multimesh) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,-1); + + return multimesh->elements.size(); +} + +void Rasterizer3DS::multimesh_set_mesh(RID p_multimesh,RID p_mesh) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh); + + multimesh->mesh=p_mesh; + +} +void Rasterizer3DS::multimesh_set_aabb(RID p_multimesh,const AABB& p_aabb) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh); + multimesh->aabb=p_aabb; +} +void Rasterizer3DS::multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh); + ERR_FAIL_INDEX(p_index,multimesh->elements.size()); + multimesh->elements[p_index].xform=p_transform; + +} +void Rasterizer3DS::multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh) + ERR_FAIL_INDEX(p_index,multimesh->elements.size()); + multimesh->elements[p_index].color=p_color; + +} + +RID Rasterizer3DS::multimesh_get_mesh(RID p_multimesh) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,RID()); + + return multimesh->mesh; +} +AABB Rasterizer3DS::multimesh_get_aabb(RID p_multimesh) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,AABB()); + + return multimesh->aabb; +} + +Transform Rasterizer3DS::multimesh_instance_get_transform(RID p_multimesh,int p_index) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,Transform()); + + ERR_FAIL_INDEX_V(p_index,multimesh->elements.size(),Transform()); + + return multimesh->elements[p_index].xform; + +} +Color Rasterizer3DS::multimesh_instance_get_color(RID p_multimesh,int p_index) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,Color()); + ERR_FAIL_INDEX_V(p_index,multimesh->elements.size(),Color()); + + return multimesh->elements[p_index].color; +} + +void Rasterizer3DS::multimesh_set_visible_instances(RID p_multimesh,int p_visible) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh); + multimesh->visible=p_visible; + +} + +int Rasterizer3DS::multimesh_get_visible_instances(RID p_multimesh) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,-1); + return multimesh->visible; + +} + +/* IMMEDIATE API */ + + +RID Rasterizer3DS::immediate_create() { + + Immediate *im = memnew( Immediate ); + return immediate_owner.make_rid(im); + +} + +void Rasterizer3DS::immediate_begin(RID p_immediate,VS::PrimitiveType p_rimitive,RID p_texture){ + + +} +void Rasterizer3DS::immediate_vertex(RID p_immediate,const Vector3& p_vertex){ + + +} +void Rasterizer3DS::immediate_normal(RID p_immediate,const Vector3& p_normal){ + + +} +void Rasterizer3DS::immediate_tangent(RID p_immediate,const Plane& p_tangent){ + + +} +void Rasterizer3DS::immediate_color(RID p_immediate,const Color& p_color){ + + +} +void Rasterizer3DS::immediate_uv(RID p_immediate,const Vector2& tex_uv){ + + +} +void Rasterizer3DS::immediate_uv2(RID p_immediate,const Vector2& tex_uv){ + + +} + +void Rasterizer3DS::immediate_end(RID p_immediate){ + + +} +void Rasterizer3DS::immediate_clear(RID p_immediate) { + + +} + +AABB Rasterizer3DS::immediate_get_aabb(RID p_immediate) const { + + return AABB(Vector3(-1,-1,-1),Vector3(2,2,2)); +} + +void Rasterizer3DS::immediate_set_material(RID p_immediate,RID p_material) { + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + im->material=p_material; + +} + +RID Rasterizer3DS::immediate_get_material(RID p_immediate) const { + + const Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND_V(!im,RID()); + return im->material; + +} + +/* PARTICLES API */ + +RID Rasterizer3DS::particles_create() { + + Particles *particles = memnew( Particles ); + ERR_FAIL_COND_V(!particles,RID()); + return particles_owner.make_rid(particles); +} + +void Rasterizer3DS::particles_set_amount(RID p_particles, int p_amount) { + + ERR_FAIL_COND(p_amount<1); + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.amount=p_amount; + +} + +int Rasterizer3DS::particles_get_amount(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.amount; + +} + +void Rasterizer3DS::particles_set_emitting(RID p_particles, bool p_emitting) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.emitting=p_emitting;; + +} +bool Rasterizer3DS::particles_is_emitting(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,false); + return particles->data.emitting; + +} + +void Rasterizer3DS::particles_set_visibility_aabb(RID p_particles, const AABB& p_visibility) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.visibility_aabb=p_visibility; + +} + +void Rasterizer3DS::particles_set_emission_half_extents(RID p_particles, const Vector3& p_half_extents) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + + particles->data.emission_half_extents=p_half_extents; +} +Vector3 Rasterizer3DS::particles_get_emission_half_extents(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,Vector3()); + + return particles->data.emission_half_extents; +} + +void Rasterizer3DS::particles_set_emission_base_velocity(RID p_particles, const Vector3& p_base_velocity) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + + particles->data.emission_base_velocity=p_base_velocity; +} + +Vector3 Rasterizer3DS::particles_get_emission_base_velocity(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,Vector3()); + + return particles->data.emission_base_velocity; +} + + +void Rasterizer3DS::particles_set_emission_points(RID p_particles, const DVector& p_points) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + + particles->data.emission_points=p_points; +} + +DVector Rasterizer3DS::particles_get_emission_points(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,DVector()); + + return particles->data.emission_points; + +} + +void Rasterizer3DS::particles_set_gravity_normal(RID p_particles, const Vector3& p_normal) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + + particles->data.gravity_normal=p_normal; + +} +Vector3 Rasterizer3DS::particles_get_gravity_normal(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,Vector3()); + + return particles->data.gravity_normal; +} + + +AABB Rasterizer3DS::particles_get_visibility_aabb(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,AABB()); + return particles->data.visibility_aabb; + +} + +void Rasterizer3DS::particles_set_variable(RID p_particles, VS::ParticleVariable p_variable,float p_value) { + + ERR_FAIL_INDEX(p_variable,VS::PARTICLE_VAR_MAX); + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.particle_vars[p_variable]=p_value; + +} +float Rasterizer3DS::particles_get_variable(RID p_particles, VS::ParticleVariable p_variable) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.particle_vars[p_variable]; +} + +void Rasterizer3DS::particles_set_randomness(RID p_particles, VS::ParticleVariable p_variable,float p_randomness) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.particle_randomness[p_variable]=p_randomness; + +} +float Rasterizer3DS::particles_get_randomness(RID p_particles, VS::ParticleVariable p_variable) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.particle_randomness[p_variable]; + +} + +void Rasterizer3DS::particles_set_color_phases(RID p_particles, int p_phases) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + ERR_FAIL_COND( p_phases<0 || p_phases>VS::MAX_PARTICLE_COLOR_PHASES ); + particles->data.color_phase_count=p_phases; + +} +int Rasterizer3DS::particles_get_color_phases(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.color_phase_count; +} + + +void Rasterizer3DS::particles_set_color_phase_pos(RID p_particles, int p_phase, float p_pos) { + + ERR_FAIL_INDEX(p_phase, VS::MAX_PARTICLE_COLOR_PHASES); + if (p_pos<0.0) + p_pos=0.0; + if (p_pos>1.0) + p_pos=1.0; + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.color_phases[p_phase].pos=p_pos; + +} +float Rasterizer3DS::particles_get_color_phase_pos(RID p_particles, int p_phase) const { + + ERR_FAIL_INDEX_V(p_phase, VS::MAX_PARTICLE_COLOR_PHASES, -1.0); + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.color_phases[p_phase].pos; + +} + +void Rasterizer3DS::particles_set_color_phase_color(RID p_particles, int p_phase, const Color& p_color) { + + ERR_FAIL_INDEX(p_phase, VS::MAX_PARTICLE_COLOR_PHASES); + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.color_phases[p_phase].color=p_color; + + //update alpha + particles->has_alpha=false; + for(int i=0;idata.color_phases[i].color.a<0.99) + particles->has_alpha=true; + } + +} + +Color Rasterizer3DS::particles_get_color_phase_color(RID p_particles, int p_phase) const { + + ERR_FAIL_INDEX_V(p_phase, VS::MAX_PARTICLE_COLOR_PHASES, Color()); + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,Color()); + return particles->data.color_phases[p_phase].color; + +} + +void Rasterizer3DS::particles_set_attractors(RID p_particles, int p_attractors) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + ERR_FAIL_COND( p_attractors<0 || p_attractors>VisualServer::MAX_PARTICLE_ATTRACTORS ); + particles->data.attractor_count=p_attractors; + +} +int Rasterizer3DS::particles_get_attractors(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.attractor_count; +} + +void Rasterizer3DS::particles_set_attractor_pos(RID p_particles, int p_attractor, const Vector3& p_pos) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + ERR_FAIL_INDEX(p_attractor,particles->data.attractor_count); + particles->data.attractors[p_attractor].pos=p_pos;; +} +Vector3 Rasterizer3DS::particles_get_attractor_pos(RID p_particles,int p_attractor) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,Vector3()); + ERR_FAIL_INDEX_V(p_attractor,particles->data.attractor_count,Vector3()); + return particles->data.attractors[p_attractor].pos; +} + +void Rasterizer3DS::particles_set_attractor_strength(RID p_particles, int p_attractor, float p_force) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + ERR_FAIL_INDEX(p_attractor,particles->data.attractor_count); + particles->data.attractors[p_attractor].force=p_force; +} + +float Rasterizer3DS::particles_get_attractor_strength(RID p_particles,int p_attractor) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,0); + ERR_FAIL_INDEX_V(p_attractor,particles->data.attractor_count,0); + return particles->data.attractors[p_attractor].force; +} + +void Rasterizer3DS::particles_set_material(RID p_particles, RID p_material,bool p_owned) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + if (particles->material_owned && particles->material.is_valid()) + free(particles->material); + + particles->material_owned=p_owned; + + particles->material=p_material; + +} +RID Rasterizer3DS::particles_get_material(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,RID()); + return particles->material; + +} + +void Rasterizer3DS::particles_set_use_local_coordinates(RID p_particles, bool p_enable) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.local_coordinates=p_enable; + +} + +bool Rasterizer3DS::particles_is_using_local_coordinates(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,false); + return particles->data.local_coordinates; +} +bool Rasterizer3DS::particles_has_height_from_velocity(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,false); + return particles->data.height_from_velocity; +} + +void Rasterizer3DS::particles_set_height_from_velocity(RID p_particles, bool p_enable) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.height_from_velocity=p_enable; + +} + +AABB Rasterizer3DS::particles_get_aabb(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,AABB()); + return particles->data.visibility_aabb; +} + +/* SKELETON API */ + +RID Rasterizer3DS::skeleton_create() { + + Skeleton *skeleton = memnew( Skeleton ); + ERR_FAIL_COND_V(!skeleton,RID()); + return skeleton_owner.make_rid( skeleton ); +} +void Rasterizer3DS::skeleton_resize(RID p_skeleton,int p_bones) { + + Skeleton *skeleton = skeleton_owner.get( p_skeleton ); + ERR_FAIL_COND(!skeleton); + if (p_bones == skeleton->bones.size()) { + return; + }; + + skeleton->bones.resize(p_bones); + +} +int Rasterizer3DS::skeleton_get_bone_count(RID p_skeleton) const { + + Skeleton *skeleton = skeleton_owner.get( p_skeleton ); + ERR_FAIL_COND_V(!skeleton, -1); + return skeleton->bones.size(); +} +void Rasterizer3DS::skeleton_bone_set_transform(RID p_skeleton,int p_bone, const Transform& p_transform) { + + Skeleton *skeleton = skeleton_owner.get( p_skeleton ); + ERR_FAIL_COND(!skeleton); + ERR_FAIL_INDEX( p_bone, skeleton->bones.size() ); + + skeleton->bones[p_bone] = p_transform; +} + +Transform Rasterizer3DS::skeleton_bone_get_transform(RID p_skeleton,int p_bone) { + + Skeleton *skeleton = skeleton_owner.get( p_skeleton ); + ERR_FAIL_COND_V(!skeleton, Transform()); + ERR_FAIL_INDEX_V( p_bone, skeleton->bones.size(), Transform() ); + + // something + return skeleton->bones[p_bone]; +} + + +/* LIGHT API */ + +RID Rasterizer3DS::light_create(VS::LightType p_type) { + + Light *light = memnew( Light ); + light->type=p_type; + return light_owner.make_rid(light); +} + +VS::LightType Rasterizer3DS::light_get_type(RID p_light) const { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND_V(!light,VS::LIGHT_OMNI); + return light->type; +} + +void Rasterizer3DS::light_set_color(RID p_light,VS::LightColor p_type, const Color& p_color) { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND(!light); + ERR_FAIL_INDEX( p_type, 3 ); + light->colors[p_type]=p_color; +} +Color Rasterizer3DS::light_get_color(RID p_light,VS::LightColor p_type) const { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND_V(!light, Color()); + ERR_FAIL_INDEX_V( p_type, 3, Color() ); + return light->colors[p_type]; +} + +void Rasterizer3DS::light_set_shadow(RID p_light,bool p_enabled) { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND(!light); + light->shadow_enabled=p_enabled; +} + +bool Rasterizer3DS::light_has_shadow(RID p_light) const { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND_V(!light,false); + return light->shadow_enabled; +} + +void Rasterizer3DS::light_set_volumetric(RID p_light,bool p_enabled) { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND(!light); + light->volumetric_enabled=p_enabled; + +} +bool Rasterizer3DS::light_is_volumetric(RID p_light) const { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND_V(!light,false); + return light->volumetric_enabled; +} + +void Rasterizer3DS::light_set_projector(RID p_light,RID p_texture) { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND(!light); + light->projector=p_texture; +} +RID Rasterizer3DS::light_get_projector(RID p_light) const { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND_V(!light,RID()); + return light->projector; +} + +void Rasterizer3DS::light_set_var(RID p_light, VS::LightParam p_var, float p_value) { + + Light * light = light_owner.get( p_light ); + ERR_FAIL_COND(!light); + ERR_FAIL_INDEX( p_var, VS::LIGHT_PARAM_MAX ); + + light->vars[p_var]=p_value; +} +float Rasterizer3DS::light_get_var(RID p_light, VS::LightParam p_var) const { + + Light * light = light_owner.get( p_light ); + ERR_FAIL_COND_V(!light,0); + + ERR_FAIL_INDEX_V( p_var, VS::LIGHT_PARAM_MAX,0 ); + + return light->vars[p_var]; +} + +void Rasterizer3DS::light_set_operator(RID p_light,VS::LightOp p_op) { + + Light * light = light_owner.get( p_light ); + ERR_FAIL_COND(!light); + + +}; + +VS::LightOp Rasterizer3DS::light_get_operator(RID p_light) const { + + return VS::LightOp(0); +}; + +void Rasterizer3DS::light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode) { + + +} + +VS::LightOmniShadowMode Rasterizer3DS::light_omni_get_shadow_mode(RID p_light) const{ + + return VS::LightOmniShadowMode(0); +} + +void Rasterizer3DS::light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode) { + + +} + +VS::LightDirectionalShadowMode Rasterizer3DS::light_directional_get_shadow_mode(RID p_light) const { + + return VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; +} + +void Rasterizer3DS::light_directional_set_shadow_param(RID p_light,VS::LightDirectionalShadowParam p_param, float p_value) { + + +} + +float Rasterizer3DS::light_directional_get_shadow_param(RID p_light,VS::LightDirectionalShadowParam p_param) const { + + return 0; +} + + +AABB Rasterizer3DS::light_get_aabb(RID p_light) const { + + Light *light = light_owner.get( p_light ); + ERR_FAIL_COND_V(!light,AABB()); + + switch( light->type ) { + + case VS::LIGHT_SPOT: { + + float len=light->vars[VS::LIGHT_PARAM_RADIUS]; + float size=Math::tan(Math::deg2rad(light->vars[VS::LIGHT_PARAM_SPOT_ANGLE]))*len; + return AABB( Vector3( -size,-size,-len ), Vector3( size*2, size*2, len ) ); + } break; + case VS::LIGHT_OMNI: { + + float r = light->vars[VS::LIGHT_PARAM_RADIUS]; + return AABB( -Vector3(r,r,r), Vector3(r,r,r)*2 ); + } break; + case VS::LIGHT_DIRECTIONAL: { + + return AABB(); + } break; + default: {} + } + + ERR_FAIL_V( AABB() ); +} + + +RID Rasterizer3DS::light_instance_create(RID p_light) { + + Light *light = light_owner.get( p_light ); + ERR_FAIL_COND_V(!light, RID()); + + LightInstance *light_instance = memnew( LightInstance ); + + light_instance->light=p_light; + light_instance->base=light; + + + return light_instance_owner.make_rid( light_instance ); +} +void Rasterizer3DS::light_instance_set_transform(RID p_light_instance,const Transform& p_transform) { + + LightInstance *lighti = light_instance_owner.get( p_light_instance ); + ERR_FAIL_COND(!lighti); + lighti->transform=p_transform; + +} + +bool Rasterizer3DS::light_instance_has_shadow(RID p_light_instance) const { + + return false; + +} + + +bool Rasterizer3DS::light_instance_assign_shadow(RID p_light_instance) { + + return false; + +} + + +Rasterizer::ShadowType Rasterizer3DS::light_instance_get_shadow_type(RID p_light_instance) const { + + LightInstance *lighti = light_instance_owner.get( p_light_instance ); + ERR_FAIL_COND_V(!lighti,Rasterizer::SHADOW_NONE); + + switch(lighti->base->type) { + + case VS::LIGHT_DIRECTIONAL: return SHADOW_PSM; break; + case VS::LIGHT_OMNI: return SHADOW_DUAL_PARABOLOID; break; + case VS::LIGHT_SPOT: return SHADOW_SIMPLE; break; + } + + return Rasterizer::SHADOW_NONE; +} + +Rasterizer::ShadowType Rasterizer3DS::light_instance_get_shadow_type(RID p_light_instance,bool p_far) const { + + return SHADOW_NONE; +} +void Rasterizer3DS::light_instance_set_shadow_transform(RID p_light_instance, int p_index, const CameraMatrix& p_camera, const Transform& p_transform, float p_split_near,float p_split_far) { + + +} + +int Rasterizer3DS::light_instance_get_shadow_passes(RID p_light_instance) const { + + return 0; +} + +bool Rasterizer3DS::light_instance_get_pssm_shadow_overlap(RID p_light_instance) const { + + return false; +} + + +void Rasterizer3DS::light_instance_set_custom_transform(RID p_light_instance, int p_index, const CameraMatrix& p_camera, const Transform& p_transform, float p_split_near,float p_split_far) { + + LightInstance *lighti = light_instance_owner.get( p_light_instance ); + ERR_FAIL_COND(!lighti); + + ERR_FAIL_COND(lighti->base->type!=VS::LIGHT_DIRECTIONAL); + ERR_FAIL_INDEX(p_index,1); + + lighti->custom_projection=p_camera; + lighti->custom_transform=p_transform; + +} +void Rasterizer3DS::shadow_clear_near() { + + +} + +bool Rasterizer3DS::shadow_allocate_near(RID p_light) { + + return false; +} + +bool Rasterizer3DS::shadow_allocate_far(RID p_light) { + + return false; +} + +/* PARTICLES INSTANCE */ + +RID Rasterizer3DS::particles_instance_create(RID p_particles) { + + ERR_FAIL_COND_V(!particles_owner.owns(p_particles),RID()); + ParticlesInstance *particles_instance = memnew( ParticlesInstance ); + ERR_FAIL_COND_V(!particles_instance, RID() ); + particles_instance->particles=p_particles; + return particles_instance_owner.make_rid(particles_instance); +} + +void Rasterizer3DS::particles_instance_set_transform(RID p_particles_instance,const Transform& p_transform) { + + ParticlesInstance *particles_instance=particles_instance_owner.get(p_particles_instance); + ERR_FAIL_COND(!particles_instance); + particles_instance->transform=p_transform; +} + + +/* RENDER API */ +/* all calls (inside begin/end shadow) are always warranted to be in the following order: */ + + +RID Rasterizer3DS::viewport_data_create() { + + return RID(); +} + +RID Rasterizer3DS::render_target_create(){ + + return RID(); + +} +void Rasterizer3DS::render_target_set_size(RID p_render_target, int p_width, int p_height){ + + +} +RID Rasterizer3DS::render_target_get_texture(RID p_render_target) const{ + + return RID(); + +} +bool Rasterizer3DS::render_target_renedered_in_frame(RID p_render_target){ + + return false; +} + + +void Rasterizer3DS::begin_frame() { + C3D_FrameBegin(C3D_FRAME_SYNCDRAW); + C3D_RenderTargetClear(top_rt->target, C3D_CLEAR_ALL, clear_color_top, 0); + C3D_FrameDrawOn(top_rt->target); +} + +void Rasterizer3DS::capture_viewport(Image* r_capture) { + + +} + + +void Rasterizer3DS::clear_viewport(const Color& p_color) { + + clear_color_top = convert_color(&p_color); + // begin_frame(); +}; + +void Rasterizer3DS::set_viewport(const VS::ViewportRect& p_viewport) { + + + +} + +void Rasterizer3DS::set_render_target(RID p_render_target, bool p_transparent_bg, bool p_vflip) { + + +} + + +void Rasterizer3DS::begin_scene(RID p_viewport_data,RID p_env,VS::ScenarioDebugMode p_debug) { + /* + C3D_TexEnv* env = C3D_GetTexEnv(0); + C3D_TexEnvSrc(env, C3D_Both, GPU_FRAGMENT_PRIMARY_COLOR, GPU_FRAGMENT_SECONDARY_COLOR, (GPU_TEVSRC)0); + // C3D_TexEnvOp(env, C3D_Both, 0, 0, 0); + C3D_TexEnvFunc(env, C3D_Both, GPU_ADD); + + C3D_TexBind(0, NULL);*/ + + // C3D_BindProgram(&program); + // _set_uniform(uLoc_modelView, Matrix32()); +}; + +void Rasterizer3DS::begin_shadow_map( RID p_light_instance, int p_shadow_pass ) { + +} + +void Rasterizer3DS::set_camera(const Transform& p_world,const CameraMatrix& p_projection) { + + // _set_uniform(uLoc_projection, p_projection); +} + +void Rasterizer3DS::add_light( RID p_light_instance ) { + + + +} + + + + +void Rasterizer3DS::add_mesh( const RID& p_mesh, const InstanceData *p_data) { + + +} + +void Rasterizer3DS::add_multimesh( const RID& p_multimesh, const InstanceData *p_data){ + + + + +} + +void Rasterizer3DS::add_particles( const RID& p_particle_instance, const InstanceData *p_data){ + + + +} + + + +void Rasterizer3DS::end_scene() { + // C3D_Flush(); + +} +void Rasterizer3DS::end_shadow_map() { + +} + + +void Rasterizer3DS::end_frame() { + + C3D_FrameEnd(0); + // C3D_FrameBufTransfer(&top_rt->target->frameBuf, top_rt->target->screen, top_rt->target->side, top_rt->target->transferFlags); + // gfxSwapBuffersGpu(); +} + +/* CANVAS API */ + + +void Rasterizer3DS::canvas_begin() { + // C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projection); + + + + // Mtx_OrthoTilt(&projection, 0.0, 400.0, 240.0, 0.0, 0.0, 1.0, true); + + // C3D_BindProgram(&program); + + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projection); + // drawSpriteImmediate(0, 0, 0, 32, 32); + /* + C3D_ImmDrawBegin(GPU_TRIANGLES); + C3D_ImmSendAttrib(200.0f, 200.0f, 0.5f, 0.0f); // v0=position + C3D_ImmSendAttrib(1.0f, 0.0f, 0.0f, 1.0f); // v1=color + + C3D_ImmSendAttrib(100.0f, 40.0f, 0.5f, 0.0f); + C3D_ImmSendAttrib(1.0f, 1.0f, 0.0f, 1.0f); + + C3D_ImmSendAttrib(300.0f, 40.0f, 0.5f, 0.0f); + C3D_ImmSendAttrib(0.0f, 0.0f, 1.0f, 1.0f); + C3D_ImmDrawEnd();*/ +} +void Rasterizer3DS::canvas_disable_blending() { + + + +} + +void Rasterizer3DS::canvas_set_opacity(float p_opacity) { + + +} + +void Rasterizer3DS::canvas_set_blend_mode(VS::MaterialBlendMode p_mode) { + + +} + + +void Rasterizer3DS::canvas_begin_rect(const Matrix32& p_transform) { + // _set_uniform(uLoc_modelView, p_transform); +} + +void Rasterizer3DS::canvas_set_clip(bool p_clip, const Rect2& p_rect) { + + + + +} + +void Rasterizer3DS::canvas_end_rect() { + + +} + +void Rasterizer3DS::canvas_draw_line(const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width) { + + + +} + +void Rasterizer3DS::canvas_draw_rect(const Rect2& p_rect, int p_flags, const Rect2& p_source,RID p_texture,const Color& p_modulate) { + + + // _set_glcoloro( p_modulate,canvas_opacity ); + + if ( p_texture.is_valid() ) { + + // sceGuEnable(GU_TEXTURE_2D); + Texture *texture = texture_owner.get( p_texture ); + ERR_FAIL_COND(!texture); + // glActiveTexture(GL_TEXTURE0); + // glBindTexture( GL_TEXTURE_2D,texture->tex_id ); +/* + C3D_TexEnv* env = C3D_GetTexEnv(0); + C3D_TexEnvSrc(env, C3D_Both, GPU_FRAGMENT_PRIMARY_COLOR, GPU_FRAGMENT_SECONDARY_COLOR); + C3D_TexEnvOpRgb(env, GPU_TEVOP_RGB_SRC_COLOR); + C3D_TexEnvOpAlpha(env,GPU_TEVOP_A_SRC_ALPHA); + C3D_TexEnvFunc(env, C3D_Both, GPU_ADD); + + C3D_TexBind(0, &texture->texture);*/ + + if (!(p_flags&CANVAS_RECT_REGION)) { + + Rect2 region = Rect2(0,0,texture->width,texture->height); + _draw_textured_quad(p_rect,region,region.size,p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V); + + } else { + + + _draw_textured_quad(p_rect, p_source, Size2(texture->width,texture->height),p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V ); + + } + + } else { + + WARN_PRINT("p_texture is not valid"); + + // sceGuDisable(GU_TEXTURE_2D); + // _draw_quad( p_rect ); + + } + +} +void Rasterizer3DS::canvas_draw_style_box(const Rect2& p_rect, RID p_texture,const float *p_margin, bool p_draw_center,const Color& p_modulate) { + + +} +void Rasterizer3DS::canvas_draw_primitive(const Vector& p_points, const Vector& p_colors,const Vector& p_uvs, RID p_texture,float p_width) { + + + +} + + +void Rasterizer3DS::canvas_draw_polygon(int p_vertex_count, const int* p_indices, const Vector2* p_vertices, const Vector2* p_uvs, const Color* p_colors,const RID& p_texture,bool p_singlecolor) { + + + +} + +void Rasterizer3DS::canvas_set_transform(const Matrix32& p_transform) { + + +} + +/* ENVIRONMENT */ + +RID Rasterizer3DS::environment_create() { + + Environment * env = memnew( Environment ); + return environment_owner.make_rid(env); +} + +void Rasterizer3DS::environment_set_background(RID p_env,VS::EnvironmentBG p_bg) { + + ERR_FAIL_INDEX(p_bg,VS::ENV_BG_MAX); + Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND(!env); + env->bg_mode=p_bg; +} + +VS::EnvironmentBG Rasterizer3DS::environment_get_background(RID p_env) const{ + + const Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND_V(!env,VS::ENV_BG_MAX); + return env->bg_mode; +} + +void Rasterizer3DS::environment_set_background_param(RID p_env,VS::EnvironmentBGParam p_param, const Variant& p_value){ + + ERR_FAIL_INDEX(p_param,VS::ENV_BG_PARAM_MAX); + Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND(!env); + env->bg_param[p_param]=p_value; + +} +Variant Rasterizer3DS::environment_get_background_param(RID p_env,VS::EnvironmentBGParam p_param) const{ + + ERR_FAIL_INDEX_V(p_param,VS::ENV_BG_PARAM_MAX,Variant()); + const Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND_V(!env,Variant()); + return env->bg_param[p_param]; + +} + +void Rasterizer3DS::environment_set_enable_fx(RID p_env,VS::EnvironmentFx p_effect,bool p_enabled){ + + ERR_FAIL_INDEX(p_effect,VS::ENV_FX_MAX); + Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND(!env); + env->fx_enabled[p_effect]=p_enabled; +} +bool Rasterizer3DS::environment_is_fx_enabled(RID p_env,VS::EnvironmentFx p_effect) const{ + + ERR_FAIL_INDEX_V(p_effect,VS::ENV_FX_MAX,false); + const Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND_V(!env,false); + return env->fx_enabled[p_effect]; + +} + +void Rasterizer3DS::environment_fx_set_param(RID p_env,VS::EnvironmentFxParam p_param,const Variant& p_value){ + + ERR_FAIL_INDEX(p_param,VS::ENV_FX_PARAM_MAX); + Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND(!env); + env->fx_param[p_param]=p_value; +} +Variant Rasterizer3DS::environment_fx_get_param(RID p_env,VS::EnvironmentFxParam p_param) const{ + + ERR_FAIL_INDEX_V(p_param,VS::ENV_FX_PARAM_MAX,Variant()); + const Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND_V(!env,Variant()); + return env->fx_param[p_param]; + +} + + +RID Rasterizer3DS::sampled_light_dp_create(int p_width,int p_height) { + + return sampled_light_owner.make_rid(memnew(SampledLight)); +} + +void Rasterizer3DS::sampled_light_dp_update(RID p_sampled_light, const Color *p_data, float p_multiplier) { + + +} + + +/*MISC*/ + +bool Rasterizer3DS::is_texture(const RID& p_rid) const { + + return texture_owner.owns(p_rid); +} +bool Rasterizer3DS::is_material(const RID& p_rid) const { + + return material_owner.owns(p_rid); +} +bool Rasterizer3DS::is_mesh(const RID& p_rid) const { + + return mesh_owner.owns(p_rid); +} + +bool Rasterizer3DS::is_immediate(const RID& p_rid) const { + + return immediate_owner.owns(p_rid); +} + +bool Rasterizer3DS::is_multimesh(const RID& p_rid) const { + + return multimesh_owner.owns(p_rid); +} +bool Rasterizer3DS::is_particles(const RID &p_beam) const { + + return particles_owner.owns(p_beam); +} + +bool Rasterizer3DS::is_light(const RID& p_rid) const { + + return light_owner.owns(p_rid); +} +bool Rasterizer3DS::is_light_instance(const RID& p_rid) const { + + return light_instance_owner.owns(p_rid); +} +bool Rasterizer3DS::is_particles_instance(const RID& p_rid) const { + + return particles_instance_owner.owns(p_rid); +} +bool Rasterizer3DS::is_skeleton(const RID& p_rid) const { + + return skeleton_owner.owns(p_rid); +} +bool Rasterizer3DS::is_environment(const RID& p_rid) const { + + return environment_owner.owns(p_rid); +} + +bool Rasterizer3DS::is_shader(const RID& p_rid) const { + + return false; +} + +void Rasterizer3DS::free(const RID& p_rid) { + + if (texture_owner.owns(p_rid)) { + + // delete the texture + Texture *texture = texture_owner.get(p_rid); + texture_owner.free(p_rid); + memdelete(texture); + + } else if (shader_owner.owns(p_rid)) { + + // delete the texture + Shader *shader = shader_owner.get(p_rid); + shader_owner.free(p_rid); + memdelete(shader); + + } else if (material_owner.owns(p_rid)) { + + Material *material = material_owner.get( p_rid ); + material_owner.free(p_rid); + memdelete(material); + + } else if (mesh_owner.owns(p_rid)) { + + Mesh *mesh = mesh_owner.get(p_rid); + + for (int i=0;isurfaces.size();i++) { + + memdelete( mesh->surfaces[i] ); + }; + + mesh->surfaces.clear(); + mesh_owner.free(p_rid); + memdelete(mesh); + + } else if (multimesh_owner.owns(p_rid)) { + + MultiMesh *multimesh = multimesh_owner.get(p_rid); + multimesh_owner.free(p_rid); + memdelete(multimesh); + + } else if (immediate_owner.owns(p_rid)) { + + Immediate *immediate = immediate_owner.get(p_rid); + immediate_owner.free(p_rid); + memdelete(immediate); + + } else if (particles_owner.owns(p_rid)) { + + Particles *particles = particles_owner.get(p_rid); + particles_owner.free(p_rid); + memdelete(particles); + } else if (particles_instance_owner.owns(p_rid)) { + + ParticlesInstance *particles_isntance = particles_instance_owner.get(p_rid); + particles_instance_owner.free(p_rid); + memdelete(particles_isntance); + + } else if (skeleton_owner.owns(p_rid)) { + + Skeleton *skeleton = skeleton_owner.get( p_rid ); + skeleton_owner.free(p_rid); + memdelete(skeleton); + + } else if (light_owner.owns(p_rid)) { + + Light *light = light_owner.get( p_rid ); + light_owner.free(p_rid); + memdelete(light); + + } else if (light_instance_owner.owns(p_rid)) { + + LightInstance *light_instance = light_instance_owner.get( p_rid ); + light_instance_owner.free(p_rid); + memdelete( light_instance ); + + + } else if (environment_owner.owns(p_rid)) { + + Environment *env = environment_owner.get( p_rid ); + environment_owner.free(p_rid); + memdelete( env ); + } else if (sampled_light_owner.owns(p_rid)) { + + SampledLight *sampled_light = sampled_light_owner.get( p_rid ); + ERR_FAIL_COND(!sampled_light); + + sampled_light_owner.free(p_rid); + memdelete( sampled_light ); + + }; +} + + +void Rasterizer3DS::custom_shade_model_set_shader(int p_model, RID p_shader) { + + +}; + +RID Rasterizer3DS::custom_shade_model_get_shader(int p_model) const { + + return RID(); +}; + +void Rasterizer3DS::custom_shade_model_set_name(int p_model, const String& p_name) { + +}; + +String Rasterizer3DS::custom_shade_model_get_name(int p_model) const { + + return String(); +}; + +void Rasterizer3DS::custom_shade_model_set_param_info(int p_model, const List& p_info) { + +}; + +void Rasterizer3DS::custom_shade_model_get_param_info(int p_model, List* p_info) const { + +}; + + + +void Rasterizer3DS::init() { + C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); + + top_rt = memnew(RenderTarget); + + top_rt->target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); + C3D_RenderTargetSetOutput(top_rt->target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); + + + simple_2ds = DVLB_ParseFile((u32*)shader_builtin_simple_2d, sizeof(shader_builtin_simple_2d)); + shaderProgramInit(&program); + shaderProgramSetVsh(&program, &simple_2ds->DVLE[0]); + C3D_BindProgram(&program); + + uLoc_projection = shaderInstanceGetUniformLocation(program.vertexShader, "projection"); + // uLoc_modelView = shaderInstanceGetUniformLocation(program.vertexShader, "modelView"); + + // Configure attributes for use with the vertex shader + C3D_AttrInfo* attrInfo = C3D_GetAttrInfo(); + AttrInfo_Init(attrInfo); + AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position + // AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2); // v1=color + AttrInfo_AddFixed(attrInfo, 1); + + // Mtx_PerspTilt(&projection, C3D_AngleFromDegrees(80.0f), C3D_AspectRatioTop, 0.01f, 1000.0f, false); + Mtx_OrthoTilt(&projection, 0.0, 400.0, 0.0, 240.0, 0.0, 1.0, true); + /* + C3D_TexEnv* env = C3D_GetTexEnv(0); + C3D_TexEnvInit(env); + C3D_TexEnvSrc(env, C3D_Both, GPU_PRIMARY_COLOR, (GPU_TEVSRC)0, (GPU_TEVSRC)0); + C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE);*/ + + C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + C3D_DepthTest(true, GPU_GEQUAL, GPU_WRITE_ALL); + // Mtx_OrthoTilt(&projection, 0.0, 400.0, 0.0, 240.0, 0.0, 1.0, true); + + + void* vbo_data = linearAlloc(sizeof(vertex_list)); + memcpy(vbo_data, vertex_list, sizeof(vertex_list)); + + // Configure buffers + C3D_BufInfo* bufInfo = C3D_GetBufInfo(); + BufInfo_Init(bufInfo); + BufInfo_Add(bufInfo, vbo_data, sizeof(vertex3ds), 1, 0x0); + + C3D_FixedAttribSet(1, 1.0, 1.0, 1.0, 1.0); + printf("Rasterizer::Init OK!\n"); +} + +void Rasterizer3DS::finish() { + + +} + +int Rasterizer3DS::get_render_info(VS::RenderInfo p_info) { + + return 0; +} + +bool Rasterizer3DS::needs_to_draw_next_frame() const { + + return false; +} + + +bool Rasterizer3DS::has_feature(VS::Features p_feature) const { + + return false; + +} + + +Rasterizer3DS::Rasterizer3DS() { + +}; + +Rasterizer3DS::~Rasterizer3DS() { + shaderProgramFree(&program); + DVLB_Free(simple_2ds); + C3D_Fini(); +}; + diff --git a/platform/3ds/rasterizer_3ds Kopie.h b/platform/3ds/rasterizer_3ds Kopie.h new file mode 100644 index 00000000..123edd68 --- /dev/null +++ b/platform/3ds/rasterizer_3ds Kopie.h @@ -0,0 +1,818 @@ +/*************************************************************************/ +/* rasterizer_3ds.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 RASTERIZER_3DS_H +#define RASTERIZER_3DS_H + +#ifdef __3DS__ +extern "C" { +#include <3ds/types.h> +#include <3ds/gpu/gpu.h> +#include <3ds/gfx.h> +#include <3ds/gpu/gx.h> +#include <3ds/gpu/shaderProgram.h> +#include <3ds/allocator/linear.h> +} +#undef __3DS__ +#include +#define __3DS__ +#endif + +#include "servers/visual/rasterizer.h" + +#include "image.h" +#include "rid.h" +#include "servers/visual_server.h" +#include "list.h" +#include "map.h" +#include "camera_matrix.h" +#include "sort.h" + + +#include "servers/visual/particle_system_sw.h" + +static uint32_t convert_color(const Color* ic) { + + uint32_t c=(uint8_t)(ic->r*255); + c<<=8; + c|=(uint8_t)(ic->g*255); + c<<=8; + c|=(uint8_t)(ic->b*255); + c<<=8; + c|=(uint8_t)(ic->a*255); + + return c; +} +typedef struct { float position[3]; float texcoord[2]; float normal[3]; } vertex3ds; + +typedef struct { + Vector3 position; + Vector2 texcoord; +} VertexArray; + +class Rasterizer3DS : public Rasterizer { + + + void _draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_flip_h,bool p_flip_v ); + DVLB_s* simple_3ds; + DVLB_s* simple_2ds; + shaderProgram_s program; + + C3D_Mtx projection; + C3D_Mtx modelView; + int uLoc_projection, uLoc_modelView; + + struct Texture { + + uint32_t flags; + int width,height; + Image::Format format; + Image image[6]; + C3D_Tex texture; + Texture() { + + flags=width=height=0; + format=Image::FORMAT_GRAYSCALE; + } + + ~Texture() { + + } + }; + + mutable RID_Owner texture_owner; + + struct RenderTarget { + C3D_RenderTarget* target; + }; + + mutable RID_Owner render_target_owner; + uint32_t clear_color_top; + + struct Shader { + + String vertex_code; + String fragment_code; + String light_code; + VS::ShaderMode mode; + Map params; + int fragment_line; + int vertex_line; + int light_line; + bool valid; + bool has_alpha; + bool use_world_transform; + + }; + + mutable RID_Owner shader_owner; + + + struct Material { + + bool flags[VS::MATERIAL_FLAG_MAX]; + + VS::MaterialDepthDrawMode depth_draw_mode; + + VS::MaterialBlendMode blend_mode; + + float line_width; + float point_size; + + RID shader; // shader material + + Map shader_params; + + + Material() { + + + for(int i=0;i material_owner; + + void _material_check_alpha(Material *p_material); + + + struct Geometry { + + enum Type { + GEOMETRY_INVALID, + GEOMETRY_SURFACE, + GEOMETRY_POLY, + GEOMETRY_PARTICLES, + GEOMETRY_MULTISURFACE, + }; + + Type type; + RID material; + bool has_alpha; + bool material_owned; + + Geometry() { has_alpha=false; material_owned = false; } + virtual ~Geometry() {}; + }; + + struct GeometryOwner { + + virtual ~GeometryOwner() {} + }; + + class Mesh; + + struct Surface : public Geometry { + + Array data; + Array morph_data; + + bool packed; + bool alpha_sort; + int morph_target_count; + AABB aabb; + + VS::PrimitiveType primitive; + + uint32_t format; + uint32_t morph_format; + + RID material; + bool material_owned; + + + Surface() { + + packed=false; + morph_target_count=0; + material_owned=false; + format=0; + morph_format=0; + + primitive=VS::PRIMITIVE_POINTS; + } + + ~Surface() { + + } + }; + + + struct Mesh { + + bool active; + Vector surfaces; + int morph_target_count; + VS::MorphTargetMode morph_target_mode; + AABB custom_aabb; + + mutable uint64_t last_pass; + Mesh() { + morph_target_mode=VS::MORPH_MODE_NORMALIZED; + morph_target_count=0; + last_pass=0; + active=false; + } + }; + mutable RID_Owner mesh_owner; + + struct MultiMesh; + + struct MultiMeshSurface : public Geometry { + + Surface *surface; + MultiMeshSurface() { type=GEOMETRY_MULTISURFACE; } + }; + + struct MultiMesh : public GeometryOwner { + + struct Element { + + Transform xform; + Color color; + }; + + AABB aabb; + RID mesh; + int visible; + + //IDirect3DVertexBuffer9* instance_buffer; + Vector elements; + + MultiMesh() { + visible=-1; + } + + + }; + + + mutable RID_Owner multimesh_owner; + + struct Immediate { + + + RID material; + int empty; + }; + + mutable RID_Owner immediate_owner; + + struct Particles : public Geometry { + + ParticleSystemSW data; // software particle system + + Particles() { + type=GEOMETRY_PARTICLES; + + } + }; + + mutable RID_Owner particles_owner; + + + struct ParticlesInstance : public GeometryOwner { + + RID particles; + + ParticleSystemProcessSW particles_process; + Transform transform; + + ParticlesInstance() { } + }; + + mutable RID_Owner particles_instance_owner; + ParticleSystemDrawInfoSW particle_draw_info; + + struct Skeleton { + + Vector bones; + + }; + + mutable RID_Owner skeleton_owner; + + + struct Light { + + VS::LightType type; + float vars[VS::LIGHT_PARAM_MAX]; + Color colors[3]; + bool shadow_enabled; + RID projector; + bool volumetric_enabled; + Color volumetric_color; + + + Light() { + + vars[VS::LIGHT_PARAM_SPOT_ATTENUATION]=1; + vars[VS::LIGHT_PARAM_SPOT_ANGLE]=45; + vars[VS::LIGHT_PARAM_ATTENUATION]=1.0; + vars[VS::LIGHT_PARAM_ENERGY]=1.0; + vars[VS::LIGHT_PARAM_RADIUS]=1.0; + vars[VS::LIGHT_PARAM_SHADOW_Z_OFFSET]=0.05; + + colors[VS::LIGHT_COLOR_DIFFUSE]=Color(1,1,1); + colors[VS::LIGHT_COLOR_SPECULAR]=Color(1,1,1); + shadow_enabled=false; + volumetric_enabled=false; + } + }; + + + struct Environment { + + + VS::EnvironmentBG bg_mode; + Variant bg_param[VS::ENV_BG_PARAM_MAX]; + bool fx_enabled[VS::ENV_FX_MAX]; + Variant fx_param[VS::ENV_FX_PARAM_MAX]; + + Environment() { + + bg_mode=VS::ENV_BG_DEFAULT_COLOR; + bg_param[VS::ENV_BG_PARAM_COLOR]=Color(0,0,0); + bg_param[VS::ENV_BG_PARAM_TEXTURE]=RID(); + bg_param[VS::ENV_BG_PARAM_CUBEMAP]=RID(); + bg_param[VS::ENV_BG_PARAM_ENERGY]=1.0; + + for(int i=0;i environment_owner; + + struct SampledLight { + + int w,h; + }; + + mutable RID_Owner sampled_light_owner; + + struct ShadowBuffer; + + struct LightInstance { + + struct SplitInfo { + + CameraMatrix camera; + Transform transform; + float near; + float far; + }; + + RID light; + Light *base; + Transform transform; + CameraMatrix projection; + + Transform custom_transform; + CameraMatrix custom_projection; + + Vector3 light_vector; + Vector3 spot_vector; + float linear_att; + + + LightInstance() { linear_att=1.0; } + + }; + + mutable RID_Owner light_owner; + mutable RID_Owner light_instance_owner; + + + RID default_material; + + RenderTarget* top_rt; + + +public: + + /* TEXTURE API */ + + virtual RID texture_create(); + virtual void texture_allocate(RID p_texture,int p_width, int p_height,Image::Format p_format,uint32_t p_flags=VS::TEXTURE_FLAGS_DEFAULT); + virtual void texture_set_data(RID p_texture,const Image& p_image,VS::CubeMapSide p_cube_side=VS::CUBEMAP_LEFT); + virtual Image texture_get_data(RID p_texture,VS::CubeMapSide p_cube_side=VS::CUBEMAP_LEFT) const; + virtual void texture_set_flags(RID p_texture,uint32_t p_flags); + virtual uint32_t texture_get_flags(RID p_texture) const; + virtual Image::Format texture_get_format(RID p_texture) const; + virtual uint32_t texture_get_width(RID p_texture) const; + virtual uint32_t texture_get_height(RID p_texture) const; + virtual bool texture_has_alpha(RID p_texture) const; + virtual void texture_set_size_override(RID p_texture,int p_width, int p_height); + virtual void texture_set_reload_hook(RID p_texture,ObjectID p_owner,const StringName& p_function) const; + + /* SHADER API */ + + virtual RID shader_create(VS::ShaderMode p_mode=VS::SHADER_MATERIAL); + + virtual void shader_set_mode(RID p_shader,VS::ShaderMode p_mode); + virtual VS::ShaderMode shader_get_mode(RID p_shader) const; + + virtual void shader_set_code(RID p_shader, const String& p_vertex, const String& p_fragment,const String& p_light,int p_vertex_ofs=0,int p_fragment_ofs=0,int p_light_ofs=0); + virtual String shader_get_fragment_code(RID p_shader) const; + virtual String shader_get_vertex_code(RID p_shader) const; + virtual String shader_get_light_code(RID p_shader) const; + + virtual void shader_get_param_list(RID p_shader, List *p_param_list) const; + + /* COMMON MATERIAL API */ + + virtual RID material_create(); + + virtual void material_set_shader(RID p_shader_material, RID p_shader); + virtual RID material_get_shader(RID p_shader_material) const; + + virtual void material_set_param(RID p_material, const StringName& p_param, const Variant& p_value); + virtual Variant material_get_param(RID p_material, const StringName& p_param) const; + + virtual void material_set_flag(RID p_material, VS::MaterialFlag p_flag,bool p_enabled); + virtual bool material_get_flag(RID p_material,VS::MaterialFlag p_flag) const; + + virtual void material_set_depth_draw_mode(RID p_material, VS::MaterialDepthDrawMode p_mode); + virtual VS::MaterialDepthDrawMode material_get_depth_draw_mode(RID p_material) const; + + virtual void material_set_blend_mode(RID p_material,VS::MaterialBlendMode p_mode); + virtual VS::MaterialBlendMode material_get_blend_mode(RID p_material) const; + + virtual void material_set_line_width(RID p_material,float p_line_width); + virtual float material_get_line_width(RID p_material) const; + + /* MESH API */ + + + virtual RID mesh_create(); + + virtual void mesh_add_surface(RID p_mesh,VS::PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes=Array(),bool p_alpha_sort=false); + virtual Array mesh_get_surface_arrays(RID p_mesh,int p_surface) const; + virtual Array mesh_get_surface_morph_arrays(RID p_mesh,int p_surface) const; + virtual void mesh_add_custom_surface(RID p_mesh,const Variant& p_dat); + + virtual void mesh_set_morph_target_count(RID p_mesh,int p_amount); + virtual int mesh_get_morph_target_count(RID p_mesh) const; + + virtual void mesh_set_morph_target_mode(RID p_mesh,VS::MorphTargetMode p_mode); + virtual VS::MorphTargetMode mesh_get_morph_target_mode(RID p_mesh) const; + + virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material,bool p_owned=false); + virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const; + + virtual int mesh_surface_get_array_len(RID p_mesh, int p_surface) const; + virtual int mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const; + virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const; + virtual VS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const; + + virtual void mesh_remove_surface(RID p_mesh,int p_index); + virtual int mesh_get_surface_count(RID p_mesh) const; + + virtual AABB mesh_get_aabb(RID p_mesh,RID p_skeleton=RID()) const; + + virtual void mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb); + virtual AABB mesh_get_custom_aabb(RID p_mesh) const; + + + /* MULTIMESH API */ + + virtual RID multimesh_create(); + + virtual void multimesh_set_instance_count(RID p_multimesh,int p_count); + virtual int multimesh_get_instance_count(RID p_multimesh) const; + + virtual void multimesh_set_mesh(RID p_multimesh,RID p_mesh); + virtual void multimesh_set_aabb(RID p_multimesh,const AABB& p_aabb); + virtual void multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform); + virtual void multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color); + + virtual RID multimesh_get_mesh(RID p_multimesh) const; + virtual AABB multimesh_get_aabb(RID p_multimesh) const;; + + virtual Transform multimesh_instance_get_transform(RID p_multimesh,int p_index) const; + virtual Color multimesh_instance_get_color(RID p_multimesh,int p_index) const; + + virtual void multimesh_set_visible_instances(RID p_multimesh,int p_visible); + virtual int multimesh_get_visible_instances(RID p_multimesh) const; + + /* IMMEDIATE API */ + + virtual RID immediate_create(); + virtual void immediate_begin(RID p_immediate,VS::PrimitiveType p_rimitive,RID p_texture=RID()); + virtual void immediate_vertex(RID p_immediate,const Vector3& p_vertex); + virtual void immediate_normal(RID p_immediate,const Vector3& p_normal); + virtual void immediate_tangent(RID p_immediate,const Plane& p_tangent); + virtual void immediate_color(RID p_immediate,const Color& p_color); + virtual void immediate_uv(RID p_immediate,const Vector2& tex_uv); + virtual void immediate_uv2(RID p_immediate,const Vector2& tex_uv); + virtual void immediate_end(RID p_immediate); + virtual void immediate_clear(RID p_immediate); + virtual void immediate_set_material(RID p_immediate,RID p_material); + virtual RID immediate_get_material(RID p_immediate) const; + + virtual AABB immediate_get_aabb(RID p_mesh) const; + + /* PARTICLES API */ + + virtual RID particles_create(); + + virtual void particles_set_amount(RID p_particles, int p_amount); + virtual int particles_get_amount(RID p_particles) const; + + virtual void particles_set_emitting(RID p_particles, bool p_emitting); + virtual bool particles_is_emitting(RID p_particles) const; + + virtual void particles_set_visibility_aabb(RID p_particles, const AABB& p_visibility); + virtual AABB particles_get_visibility_aabb(RID p_particles) const; + + virtual void particles_set_emission_half_extents(RID p_particles, const Vector3& p_half_extents); + virtual Vector3 particles_get_emission_half_extents(RID p_particles) const; + + virtual void particles_set_emission_base_velocity(RID p_particles, const Vector3& p_base_velocity); + virtual Vector3 particles_get_emission_base_velocity(RID p_particles) const; + + virtual void particles_set_emission_points(RID p_particles, const DVector& p_points); + virtual DVector particles_get_emission_points(RID p_particles) const; + + virtual void particles_set_gravity_normal(RID p_particles, const Vector3& p_normal); + virtual Vector3 particles_get_gravity_normal(RID p_particles) const; + + virtual void particles_set_variable(RID p_particles, VS::ParticleVariable p_variable,float p_value); + virtual float particles_get_variable(RID p_particles, VS::ParticleVariable p_variable) const; + + virtual void particles_set_randomness(RID p_particles, VS::ParticleVariable p_variable,float p_randomness); + virtual float particles_get_randomness(RID p_particles, VS::ParticleVariable p_variable) const; + + virtual void particles_set_color_phase_pos(RID p_particles, int p_phase, float p_pos); + virtual float particles_get_color_phase_pos(RID p_particles, int p_phase) const; + + virtual void particles_set_color_phases(RID p_particles, int p_phases); + virtual int particles_get_color_phases(RID p_particles) const; + + virtual void particles_set_color_phase_color(RID p_particles, int p_phase, const Color& p_color); + virtual Color particles_get_color_phase_color(RID p_particles, int p_phase) const; + + virtual void particles_set_attractors(RID p_particles, int p_attractors); + virtual int particles_get_attractors(RID p_particles) const; + + virtual void particles_set_attractor_pos(RID p_particles, int p_attractor, const Vector3& p_pos); + virtual Vector3 particles_get_attractor_pos(RID p_particles,int p_attractor) const; + + virtual void particles_set_attractor_strength(RID p_particles, int p_attractor, float p_force); + virtual float particles_get_attractor_strength(RID p_particles,int p_attractor) const; + + virtual void particles_set_material(RID p_particles, RID p_material,bool p_owned=false); + virtual RID particles_get_material(RID p_particles) const; + + virtual AABB particles_get_aabb(RID p_particles) const; + + virtual void particles_set_height_from_velocity(RID p_particles, bool p_enable); + virtual bool particles_has_height_from_velocity(RID p_particles) const; + + virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable); + virtual bool particles_is_using_local_coordinates(RID p_particles) const; + + /* SKELETON API */ + + virtual RID skeleton_create(); + virtual void skeleton_resize(RID p_skeleton,int p_bones); + virtual int skeleton_get_bone_count(RID p_skeleton) const; + virtual void skeleton_bone_set_transform(RID p_skeleton,int p_bone, const Transform& p_transform); + virtual Transform skeleton_bone_get_transform(RID p_skeleton,int p_bone); + + + /* LIGHT API */ + + virtual RID light_create(VS::LightType p_type); + virtual VS::LightType light_get_type(RID p_light) const; + + virtual void light_set_color(RID p_light,VS::LightColor p_type, const Color& p_color); + virtual Color light_get_color(RID p_light,VS::LightColor p_type) const; + + virtual void light_set_shadow(RID p_light,bool p_enabled); + virtual bool light_has_shadow(RID p_light) const; + + virtual void light_set_volumetric(RID p_light,bool p_enabled); + virtual bool light_is_volumetric(RID p_light) const; + + virtual void light_set_projector(RID p_light,RID p_texture); + virtual RID light_get_projector(RID p_light) const; + + virtual void light_set_var(RID p_light, VS::LightParam p_var, float p_value); + virtual float light_get_var(RID p_light, VS::LightParam p_var) const; + + virtual void light_set_operator(RID p_light,VS::LightOp p_op); + virtual VS::LightOp light_get_operator(RID p_light) const; + + virtual void light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode); + virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) const; + + + virtual void light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode); + virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) const; + virtual void light_directional_set_shadow_param(RID p_light,VS::LightDirectionalShadowParam p_param, float p_value); + virtual float light_directional_get_shadow_param(RID p_light,VS::LightDirectionalShadowParam p_param) const; + + virtual AABB light_get_aabb(RID p_poly) const; + + + virtual RID light_instance_create(RID p_light); + virtual void light_instance_set_transform(RID p_light_instance,const Transform& p_transform); + + virtual bool light_instance_has_shadow(RID p_light_instance) const; + virtual bool light_instance_assign_shadow(RID p_light_instance); + virtual ShadowType light_instance_get_shadow_type(RID p_light_instance) const; + virtual int light_instance_get_shadow_passes(RID p_light_instance) const; + virtual bool light_instance_get_pssm_shadow_overlap(RID p_light_instance) const; + virtual void light_instance_set_custom_transform(RID p_light_instance, int p_index, const CameraMatrix& p_camera, const Transform& p_transform, float p_split_near=0,float p_split_far=0); + virtual int light_instance_get_shadow_size(RID p_light_instance, int p_index=0) const { return 1; } + + virtual ShadowType light_instance_get_shadow_type(RID p_light_instance,bool p_far=false) const; + virtual void light_instance_set_shadow_transform(RID p_light_instance, int p_index, const CameraMatrix& p_camera, const Transform& p_transform, float p_split_near=0,float p_split_far=0); + + virtual void shadow_clear_near(); + virtual bool shadow_allocate_near(RID p_light); + virtual bool shadow_allocate_far(RID p_light); + + + /* PARTICLES INSTANCE */ + + virtual RID particles_instance_create(RID p_particles); + virtual void particles_instance_set_transform(RID p_particles_instance,const Transform& p_transform); + + /* VIEWPORT */ + + virtual RID viewport_data_create(); + + virtual RID render_target_create(); + virtual void render_target_set_size(RID p_render_target, int p_width, int p_height); + virtual RID render_target_get_texture(RID p_render_target) const; + virtual bool render_target_renedered_in_frame(RID p_render_target); + + /* RENDER API */ + /* all calls (inside begin/end shadow) are always warranted to be in the following order: */ + + virtual void begin_frame(); + + virtual void set_viewport(const VS::ViewportRect& p_viewport); + virtual void set_render_target(RID p_render_target,bool p_transparent_bg=false,bool p_vflip=false); + virtual void clear_viewport(const Color& p_color); + virtual void capture_viewport(Image* r_capture); + + + virtual void begin_scene(RID p_viewport_data,RID p_env,VS::ScenarioDebugMode p_debug); + virtual void begin_shadow_map( RID p_light_instance, int p_shadow_pass ); + + virtual void set_camera(const Transform& p_world,const CameraMatrix& p_projection); + + virtual void add_light( RID p_light_instance ); ///< all "add_light" calls happen before add_geometry calls + + + virtual void add_mesh( const RID& p_mesh, const InstanceData *p_data); + virtual void add_multimesh( const RID& p_multimesh, const InstanceData *p_data); + virtual void add_immediate( const RID& p_immediate, const InstanceData *p_data) {} + virtual void add_particles( const RID& p_particle_instance, const InstanceData *p_data); + + virtual void end_scene(); + virtual void end_shadow_map(); + + virtual void end_frame(); + + /* CANVAS API */ + + virtual void canvas_begin(); + virtual void canvas_disable_blending(); + virtual void canvas_set_opacity(float p_opacity); + virtual void canvas_set_blend_mode(VS::MaterialBlendMode p_mode); + virtual void canvas_begin_rect(const Matrix32& p_transform); + virtual void canvas_set_clip(bool p_clip, const Rect2& p_rect); + virtual void canvas_end_rect(); + virtual void canvas_draw_line(const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width); + virtual void canvas_draw_rect(const Rect2& p_rect, int p_flags, const Rect2& p_source,RID p_texture,const Color& p_modulate); + virtual void canvas_draw_style_box(const Rect2& p_rect, RID p_texture,const float *p_margins, bool p_draw_center=true,const Color& p_modulate=Color(1,1,1)); + virtual void canvas_draw_primitive(const Vector& p_points, const Vector& p_colors,const Vector& p_uvs, RID p_texture,float p_width); + virtual void canvas_draw_polygon(int p_vertex_count, const int* p_indices, const Vector2* p_vertices, const Vector2* p_uvs, const Color* p_colors,const RID& p_texture,bool p_singlecolor); + virtual void canvas_set_transform(const Matrix32& p_transform); + + /* ENVIRONMENT */ + + virtual RID environment_create(); + + virtual void environment_set_background(RID p_env,VS::EnvironmentBG p_bg); + virtual VS::EnvironmentBG environment_get_background(RID p_env) const; + + virtual void environment_set_background_param(RID p_env,VS::EnvironmentBGParam p_param, const Variant& p_value); + virtual Variant environment_get_background_param(RID p_env,VS::EnvironmentBGParam p_param) const; + + virtual void environment_set_enable_fx(RID p_env,VS::EnvironmentFx p_effect,bool p_enabled); + virtual bool environment_is_fx_enabled(RID p_env,VS::EnvironmentFx p_effect) const; + + virtual void environment_fx_set_param(RID p_env,VS::EnvironmentFxParam p_param,const Variant& p_value); + virtual Variant environment_fx_get_param(RID p_env,VS::EnvironmentFxParam p_param) const; + + /* SAMPLED LIGHT */ + virtual RID sampled_light_dp_create(int p_width,int p_height); + virtual void sampled_light_dp_update(RID p_sampled_light,const Color *p_data,float p_multiplier); + + + /*MISC*/ + + virtual bool is_texture(const RID& p_rid) const; + virtual bool is_material(const RID& p_rid) const; + virtual bool is_mesh(const RID& p_rid) const; + virtual bool is_immediate(const RID& p_rid) const; + virtual bool is_multimesh(const RID& p_rid) const; + virtual bool is_particles(const RID &p_beam) const; + + virtual bool is_light(const RID& p_rid) const; + virtual bool is_light_instance(const RID& p_rid) const; + virtual bool is_particles_instance(const RID& p_rid) const; + virtual bool is_skeleton(const RID& p_rid) const; + virtual bool is_environment(const RID& p_rid) const; + + virtual bool is_shader(const RID& p_rid) const; + + virtual void free(const RID& p_rid); + + virtual void custom_shade_model_set_shader(int p_model, RID p_shader); + virtual RID custom_shade_model_get_shader(int p_model) const; + virtual void custom_shade_model_set_name(int p_model, const String& p_name); + virtual String custom_shade_model_get_name(int p_model) const; + virtual void custom_shade_model_set_param_info(int p_model, const List& p_info); + virtual void custom_shade_model_get_param_info(int p_model, List* p_info) const; + + + virtual void init(); + virtual void finish(); + + virtual int get_render_info(VS::RenderInfo p_info); + + virtual bool needs_to_draw_next_frame() const; + + virtual bool has_feature(VS::Features p_feature) const; + + + Rasterizer3DS(); + virtual ~Rasterizer3DS(); +}; + + +#endif // RASTERIZER_DUMMY_H diff --git a/platform/3ds/rasterizer_3ds.cpp b/platform/3ds/rasterizer_3ds.cpp new file mode 100644 index 00000000..8278b360 --- /dev/null +++ b/platform/3ds/rasterizer_3ds.cpp @@ -0,0 +1,4923 @@ +/*************************************************************************/ +/* rasterizer_citro3d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 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 _3DS + +#include "rasterizer_3ds.h" +#include "globals.h" +#include "os/os.h" +#include <3ds/services/gspgpu.h> +// #include "util.h" +#define TEX_MIN_SIZE 8 +u32 next_pow2(u32 v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v >= TEX_MIN_SIZE ? v : TEX_MIN_SIZE; +} + +// Grabbed from Citra Emulator (citra/src/video_core/utils.h) +static inline u32 morton_interleave(u32 x, u32 y) +{ + u32 i = (x & 7) | ((y & 7) << 8); // ---- -210 + i = (i ^ (i << 2)) & 0x1313; // ---2 --10 + i = (i ^ (i << 1)) & 0x1515; // ---2 -1-0 + i = (i | ( i >> 7)) & 0x3F; + return i; +} + +//Grabbed from Citra Emulator (citra/src/video_core/utils.h) +static inline u32 get_morton_offset(u32 x, u32 y, u32 bytes_per_pixel) +{ + u32 i = morton_interleave(x, y); + unsigned int offset = (x & ~7) * 8; + return (i + offset) * bytes_per_pixel; +} + +void texture_tile_sw(C3D_Tex *tex, const void *data, int w, int h) +{ + const u32* src = reinterpret_cast(data); + u32* dest = reinterpret_cast(tex->data); + for (int y = 0; y < h; y++) + for (int x = 0; x < w; x++) + { + int dest_y = (tex->height - 1 - y); + u32 coarse_y = dest_y & ~7; + u32 dst_offset = get_morton_offset(x, dest_y, 1) + coarse_y * tex->width; + + u32 v = src[x + y * w]; + dest[dst_offset] = __builtin_bswap32(v); + } + + C3D_TexFlush(tex); +} + + +// Minimum texture dimension seems to be 64 pixels +void texture_tile_hw(C3D_Tex *tex, const void *data, int w, int h) +{ + const u32 flags = (GX_TRANSFER_FLIP_VERT(1) | GX_TRANSFER_OUT_TILED(1) | GX_TRANSFER_RAW_COPY(0) | + GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGBA8) | + GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO)); + + GSPGPU_FlushDataCache(data, w*h*4); + + GX_DisplayTransfer( + (u32*)data, + GX_BUFFER_DIM(w, h), + (u32*)tex->data, + GX_BUFFER_DIM(tex->width, tex->height), + flags + ); + + gspWaitForPPF(); + C3D_TexFlush(tex); +} +// Built-in shaders generated in byte array headers +#include "shaders/2d.h" +#include "shaders/3d.h" +#define CLEAR_COLOR 0x68B0D8FF +#define DISPLAY_TRANSFER_FLAGS \ + (GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | GX_TRANSFER_RAW_COPY(0) | \ + GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | \ + GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_XY)) + +/* TEXTURE API */ + +// #define print(...) printf(__VA_ARGS__) +#define print(...) + +RID Rasterizer3DS::texture_create() +{ + Texture *texture = memnew(Texture); + ERR_FAIL_COND_V(!texture,RID()); + return texture_owner.make_rid( texture ); +} + +void Rasterizer3DS::texture_allocate(RID p_texture,int p_width, int p_height,Image::Format p_format,uint32_t p_flags) +{ + u32 w = next_pow2(p_width); + u32 h = next_pow2(p_height); +// print("texture_allocate %u %u %u\n", w, h, p_texture.get_id()); + Texture *texture = texture_owner.get( p_texture ); + ERR_FAIL_COND(!texture); + ERR_FAIL_COND(w > 1024 || h > 1024); + ERR_FAIL_COND(!C3D_TexInit(&texture->tex, w, h, GPU_RGBA8)); + texture->width=p_width; + texture->height=p_height; + texture->format=p_format; + texture->flags=p_flags; +} + +void Rasterizer3DS::texture_set_data(RID p_texture,const Image& p_image,VS::CubeMapSide p_cube_side) +{ + Texture * texture = texture_owner.get(p_texture); + ERR_FAIL_COND(!texture); + ERR_FAIL_COND(texture->format != p_image.get_format() ); + + Image &image = texture->image[p_cube_side]; + image = p_image; + image.convert(Image::FORMAT_RGBA); + ERR_FAIL_COND(image.get_format() != Image::FORMAT_RGBA); + + DVector d = image.get_data(); + const u32* imagedata = reinterpret_cast(d.read().ptr()); + + texture_tile_sw(&texture->tex, imagedata, texture->width, texture->height); + +// texture->image[p_cube_side]=image; +} + +Image Rasterizer3DS::texture_get_data(RID p_texture,VS::CubeMapSide p_cube_side) const +{ + print("texture_get_data\n"); + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,Image()); + + return texture->image[p_cube_side]; +} + +void Rasterizer3DS::texture_set_flags(RID p_texture,uint32_t p_flags) +{ + Texture *texture = texture_owner.get( p_texture ); + ERR_FAIL_COND(!texture); + uint32_t cube = texture->flags & VS::TEXTURE_FLAG_CUBEMAP; + texture->flags=p_flags|cube; // can't remove a cube from being a cube +} +uint32_t Rasterizer3DS::texture_get_flags(RID p_texture) const { + Texture * texture = texture_owner.get(p_texture); + ERR_FAIL_COND_V(!texture,0); + return texture->flags; +} +Image::Format Rasterizer3DS::texture_get_format(RID p_texture) const +{ + Texture * texture = texture_owner.get(p_texture); + ERR_FAIL_COND_V(!texture,Image::FORMAT_GRAYSCALE); + return texture->format; +} +uint32_t Rasterizer3DS::texture_get_width(RID p_texture) const +{ + Texture * texture = texture_owner.get(p_texture); + ERR_FAIL_COND_V(!texture,0); + return texture->width; +} +uint32_t Rasterizer3DS::texture_get_height(RID p_texture) const +{ + Texture * texture = texture_owner.get(p_texture); + ERR_FAIL_COND_V(!texture,0); + return texture->height; +} + +bool Rasterizer3DS::texture_has_alpha(RID p_texture) const +{ + Texture * texture = texture_owner.get(p_texture); + ERR_FAIL_COND_V(!texture,0); + return false; +} + +void Rasterizer3DS::texture_set_size_override(RID p_texture,int p_width, int p_height) +{ + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND(!texture); + + ERR_FAIL_COND(p_width<=0 || p_width>1024); + ERR_FAIL_COND(p_height<=0 || p_height>1024); + //real texture size is in alloc width and height +// texture->width=p_width; +// texture->height=p_height; +} + +void Rasterizer3DS::texture_set_reload_hook(RID p_texture,ObjectID p_owner,const StringName& p_function) const { + + +} + +/* SHADER API */ + +/* SHADER API */ + +RID Rasterizer3DS::shader_create(VS::ShaderMode p_mode) +{ + print("shader_create\n"); + Shader *shader = memnew( Shader ); + shader->mode=p_mode; + shader->fragment_line=0; + shader->vertex_line=0; + shader->light_line=0; + RID rid = shader_owner.make_rid(shader); + + return rid; +} + + + +void Rasterizer3DS::shader_set_mode(RID p_shader,VS::ShaderMode p_mode) { + + ERR_FAIL_INDEX(p_mode,3); + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND(!shader); + shader->mode=p_mode; + +} +VS::ShaderMode Rasterizer3DS::shader_get_mode(RID p_shader) const { + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND_V(!shader,VS::SHADER_MATERIAL); + return shader->mode; +} + +void Rasterizer3DS::shader_set_code(RID p_shader, const String& p_vertex, const String& p_fragment,const String& p_light,int p_vertex_ofs,int p_fragment_ofs,int p_light_ofs) { + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND(!shader); + shader->fragment_code=p_fragment; + shader->vertex_code=p_vertex; + shader->light_code=p_light; + shader->fragment_line=p_fragment_ofs; + shader->vertex_line=p_vertex_ofs; + shader->light_line=p_vertex_ofs; + +} + + +String Rasterizer3DS::shader_get_vertex_code(RID p_shader) const { + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND_V(!shader,String()); + return shader->vertex_code; + +} + +String Rasterizer3DS::shader_get_fragment_code(RID p_shader) const { + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND_V(!shader,String()); + return shader->fragment_code; + +} + +String Rasterizer3DS::shader_get_light_code(RID p_shader) const { + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND_V(!shader,String()); + return shader->light_code; + +} + +void Rasterizer3DS::shader_get_param_list(RID p_shader, List *p_param_list) const { + + Shader *shader=shader_owner.get(p_shader); + ERR_FAIL_COND(!shader); + +} + + +void Rasterizer3DS::shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture) +{ + print("shader_set_default_texture_param\n"); +} + +RID Rasterizer3DS::shader_get_default_texture_param(RID p_shader, const StringName& p_name) const { + + return RID(); +} + +Variant Rasterizer3DS::shader_get_default_param(RID p_shader, const StringName& p_name) { + + return Variant(); +} + +/* COMMON MATERIAL API */ + + +RID Rasterizer3DS::material_create() { + print("material_create\n"); + return material_owner.make_rid( memnew( Material ) ); +} + +void Rasterizer3DS::material_set_shader(RID p_material, RID p_shader) { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + material->shader=p_shader; + +} + +RID Rasterizer3DS::material_get_shader(RID p_material) const { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,RID()); + return material->shader; +} + +void Rasterizer3DS::material_set_param(RID p_material, const StringName& p_param, const Variant& p_value) +{ + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + + Map::Element *E=material->shader_params.find(p_param); + if (E) + { + if (p_value.get_type()==Variant::NIL) { + material->shader_params.erase(E); +// material->shader_version=0; //get default! + } else { + E->get().value=p_value; + E->get().inuse=true; + } + } else { + if (p_value.get_type()==Variant::NIL) + return; + + Material::UniformData ud; + ud.index=-1; + ud.value=p_value; + ud.istexture=p_value.get_type()==Variant::_RID; /// cache it being texture + ud.inuse=true; + material->shader_params[p_param]=ud; //may be got at some point, or erased + } +} +Variant Rasterizer3DS::material_get_param(RID p_material, const StringName& p_param) const +{ + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,Variant()); + +/* + if (material->shader.is_valid()) { + //update shader params if necesary + //make sure the shader is compiled and everything + //so the actual parameters can be properly retrieved! + material->shader_cache=shader_owner.get( material->shader ); + if (!material->shader_cache) { + //invalidate + material->shader=RID(); + material->shader_cache=NULL; + } else { + + if (material->shader_cache->dirty_list.in_list()) + _update_shader(material->shader_cache); + if (material->shader_cache->valid && material->shader_cache->version!=material->shader_version) { + //validate + _update_material_shader_params(material); + } + } + } +*/ + + if (material->shader_params.has(p_param) && material->shader_params[p_param].inuse) + return material->shader_params[p_param].value; + else + return Variant(); +} + + +void Rasterizer3DS::material_set_flag(RID p_material, VS::MaterialFlag p_flag,bool p_enabled) { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + ERR_FAIL_INDEX(p_flag,VS::MATERIAL_FLAG_MAX); + material->flags[p_flag]=p_enabled; + +} +bool Rasterizer3DS::material_get_flag(RID p_material,VS::MaterialFlag p_flag) const { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,false); + ERR_FAIL_INDEX_V(p_flag,VS::MATERIAL_FLAG_MAX,false); + return material->flags[p_flag]; + + +} + +void Rasterizer3DS::material_set_depth_draw_mode(RID p_material, VS::MaterialDepthDrawMode p_mode) { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + material->depth_draw_mode=p_mode; +} + +VS::MaterialDepthDrawMode Rasterizer3DS::material_get_depth_draw_mode(RID p_material) const{ + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,VS::MATERIAL_DEPTH_DRAW_ALWAYS); + return material->depth_draw_mode; +} + + +void Rasterizer3DS::material_set_blend_mode(RID p_material,VS::MaterialBlendMode p_mode) +{ + print("material_set_blend_mode\n"); + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + material->blend_mode=p_mode; +} +VS::MaterialBlendMode Rasterizer3DS::material_get_blend_mode(RID p_material) const { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,VS::MATERIAL_BLEND_MODE_ADD); + return material->blend_mode; +} + +void Rasterizer3DS::material_set_line_width(RID p_material,float p_line_width) { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + material->line_width=p_line_width; + +} +float Rasterizer3DS::material_get_line_width(RID p_material) const { + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material,0); + + return material->line_width; +} + +/* MESH API */ + + +RID Rasterizer3DS::mesh_create() +{ + print("mesh_create\n"); + return mesh_owner.make_rid( memnew( Mesh ) ); +} + +Error Rasterizer3DS::_surface_set_arrays(Surface *p_surface, uint8_t *p_mem,uint8_t *p_index_mem,const Array& p_arrays,bool p_main) { + + uint32_t stride = p_main ? p_surface->stride : p_surface->local_stride; + + for(int ai=0;ai=p_arrays.size()) + break; + if (p_arrays[ai].get_type()==Variant::NIL) + continue; + Surface::ArrayData &a=p_surface->array[ai]; + + switch(ai) { + + case VS::ARRAY_VERTEX: { + + ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::VECTOR3_ARRAY, ERR_INVALID_PARAMETER ); + + DVector array = p_arrays[ai]; + ERR_FAIL_COND_V( array.size() != p_surface->array_len, ERR_INVALID_PARAMETER ); + + + DVector::Read read = array.read(); + const Vector3* src=read.ptr(); + + // setting vertices means regenerating the AABB + AABB aabb; + + float scale=1; + + for (int i=0;iarray_len;i++) { + float vector[3]={ src[i].x, src[i].y, src[i].z }; + + memcpy(&p_mem[a.ofs+i*stride], vector, a.size); + + if (i==0) { + aabb=AABB(src[i],Vector3()); + } else { + aabb.expand_to( src[i] ); + } + } + + if (p_main) { + p_surface->aabb=aabb; + p_surface->vertex_scale=scale; + } + + } break; + case VS::ARRAY_NORMAL: { + + ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::VECTOR3_ARRAY, ERR_INVALID_PARAMETER ); + + DVector array = p_arrays[ai]; + ERR_FAIL_COND_V( array.size() != p_surface->array_len, ERR_INVALID_PARAMETER ); + + + DVector::Read read = array.read(); + const Vector3* src=read.ptr(); + + // setting vertices means regenerating the AABB + for (int i=0;iarray_len;i++) { + float vector[3]={ src[i].x, src[i].y, src[i].z }; + memcpy(&p_mem[a.ofs+i*stride], vector, a.size); + } + } break; + case VS::ARRAY_TANGENT: { + + ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::REAL_ARRAY, ERR_INVALID_PARAMETER ); + + DVector array = p_arrays[ai]; + + ERR_FAIL_COND_V( array.size() != p_surface->array_len*4, ERR_INVALID_PARAMETER ); + + DVector::Read read = array.read(); + const real_t* src = read.ptr(); + + for (int i=0;iarray_len;i++) { + + float xyzw[4]={ + src[i*4+0], + src[i*4+1], + src[i*4+2], + src[i*4+3] + }; + + memcpy(&p_mem[a.ofs+i*stride], xyzw, a.size); + + } + + } break; + case VS::ARRAY_COLOR: { + + ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::COLOR_ARRAY, ERR_INVALID_PARAMETER ); + + DVector array = p_arrays[ai]; + + ERR_FAIL_COND_V( array.size() != p_surface->array_len, ERR_INVALID_PARAMETER ); + + DVector::Read read = array.read(); + const Color* src = read.ptr(); + bool alpha=false; + + for (int i=0;iarray_len;i++) { + + if (src[i].a<0.98) // tolerate alpha a bit, for crappy exporters + alpha=true; + + uint8_t colors[4]; + + for(int j=0;j<4;j++) { + colors[j]=CLAMP( int((src[i][j])*255.0), 0,255 ); + } + + memcpy(&p_mem[a.ofs+i*stride], colors, a.size); + } + + if (p_main) + p_surface->has_alpha=alpha; + + } break; + case VS::ARRAY_TEX_UV: + case VS::ARRAY_TEX_UV2: { + + ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::VECTOR3_ARRAY && p_arrays[ai].get_type() != Variant::VECTOR2_ARRAY, ERR_INVALID_PARAMETER ); + + DVector array = p_arrays[ai]; + + ERR_FAIL_COND_V( array.size() != p_surface->array_len , ERR_INVALID_PARAMETER); + + DVector::Read read = array.read(); + + const Vector2 * src=read.ptr(); + float scale=1.0; + + for (int i=0;iarray_len;i++) { + + float uv[2]={ src[i].x , src[i].y }; + + memcpy(&p_mem[a.ofs+i*stride], uv, a.size); + + } + + if (p_main) { + if (ai==VS::ARRAY_TEX_UV) { + p_surface->uv_scale=scale; + } + if (ai==VS::ARRAY_TEX_UV2) { + p_surface->uv2_scale=scale; + } + } + + } break; + case VS::ARRAY_WEIGHTS: { + ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::REAL_ARRAY, ERR_INVALID_PARAMETER ); + + DVector array = p_arrays[ai]; + + ERR_FAIL_COND_V( array.size() != p_surface->array_len*VS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER ); + + + DVector::Read read = array.read(); + + const real_t * src = read.ptr(); + + for (int i=0;iarray_len;i++) { + + float data[VS::ARRAY_WEIGHTS_SIZE]; + for (int j=0;j array = p_arrays[ai]; + + ERR_FAIL_COND_V( array.size() != p_surface->array_len*VS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER ); + + + DVector::Read read = array.read(); + + const int * src = read.ptr(); + + p_surface->max_bone=0; + + for (int i=0;iarray_len;i++) { + + u8 data[VS::ARRAY_WEIGHTS_SIZE]; + for (int j=0;jmax_bone=MAX(data[j],p_surface->max_bone); + + } + + memcpy(&p_mem[a.ofs+i*stride], data, a.size); + } + + } break; + case VS::ARRAY_INDEX: { + +// ERR_FAIL_COND_V(a.size > 2, ERR_INVALID_DATA); + ERR_FAIL_COND_V( p_surface->index_array_len<=0, ERR_INVALID_DATA ); + ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::INT_ARRAY, ERR_INVALID_PARAMETER ); + + DVector indices = p_arrays[ai]; + ERR_FAIL_COND_V( indices.size() == 0, ERR_INVALID_PARAMETER ); + ERR_FAIL_COND_V( indices.size() != p_surface->index_array_len, ERR_INVALID_PARAMETER ); + + /* determine wether using 8 or 16 bits indices */ + + DVector::Read read = indices.read(); + const int *src=read.ptr(); + + for (int i=0;iindex_array_len;i++) { + if (a.size==2) { + uint16_t v=src[i]; + memcpy(&p_index_mem[i*a.size], &v, a.size); + } else { + uint8_t v=src[i]; + memcpy(&p_index_mem[i*a.size], &v, a.size); + } + } + } break; + + default: { ERR_FAIL_V(ERR_INVALID_PARAMETER);} + } + + p_surface->configured_format|=(1<format&VS::ARRAY_FORMAT_BONES) { + //create AABBs for each detected bone + int total_bones = p_surface->max_bone+1; + if (p_main) { + p_surface->skeleton_bone_aabb.resize(total_bones); + p_surface->skeleton_bone_used.resize(total_bones); + for(int i=0;iskeleton_bone_used[i]=false; + } + DVector vertices = p_arrays[VS::ARRAY_VERTEX]; + DVector bones = p_arrays[VS::ARRAY_BONES]; + DVector weights = p_arrays[VS::ARRAY_WEIGHTS]; + + bool any_valid=false; + + if (vertices.size() && bones.size()==vertices.size()*4 && weights.size()==bones.size()) { + //print_line("MAKING SKELETHONG"); + int vs = vertices.size(); + DVector::Read rv =vertices.read(); + DVector::Read rb=bones.read(); + DVector::Read rw=weights.read(); + + Vector first; + first.resize(total_bones); + for(int i=0;iskeleton_bone_aabb.ptr(); + bool *fptr=first.ptr(); + bool *usedptr=p_surface->skeleton_bone_used.ptr(); + + for(int i=0;iskeleton_bone_aabb.clear(); + p_surface->skeleton_bone_used.clear(); + } + } + + return OK; +} + +void Rasterizer3DS::mesh_add_surface(RID p_mesh,VS::PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes,bool p_alpha_sort) +{ + print("mesh_add_surface\n"); + ERR_FAIL_COND(p_primitive < VS::PRIMITIVE_TRIANGLES); + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + + ERR_FAIL_INDEX( p_primitive, VS::PRIMITIVE_MAX ); + ERR_FAIL_COND(p_arrays.size()!=VS::ARRAY_MAX); + + uint32_t format=0; + + // validation + int index_array_len=0; + int array_len=0; + + for(int i=0;imorph_target_count!=p_blend_shapes.size() ); + if (mesh->morph_target_count) { + //validate format for morphs + for(int i=0;iarray[i]; + ad.size=0; + ad.ofs=0; + int elem_size=0; + int elem_count=0; + bool valid_local=true; + bool normalize=false; + bool bind=false; + + if (!(format&(1< (1<<16)); // 32 bit index not supported + + /* determine wether using 8 or 16 bits indices */ + if (array_len > (1<<8)) { + elem_size=2; // C3D_UNSIGNED_SHORT + } else { + elem_size=1; // C3D_UNSIGNED_BYTE + } + + surface->index_array_len=index_array_len; // only way it can exist + ad.ofs=0; + ad.size=elem_size; + + continue; + } break; + default: { + ERR_FAIL( ); + } + } + + ad.ofs=total_elem_size; + ad.size=elem_size; +// ad.datatype=datatype; + ad.normalize=normalize; + ad.bind=bind; + ad.count=elem_count; + total_elem_size+=elem_size; + if (valid_local) { + surface->local_stride+=elem_size; + surface->morph_format|=(1<stride=total_elem_size; + surface->array_len=array_len; + surface->format=format; + surface->primitive=p_primitive; + surface->morph_target_count=mesh->morph_target_count; + surface->configured_format=0; + surface->mesh=mesh; +// if (keep_copies) { +// surface->data=p_arrays; +// surface->morph_data=p_blend_shapes; +// } + + surface->array_local = (u8*)linearAlloc(surface->array_len*surface->stride); +// u8 *array_ptr= (u8*)linearAlloc(surface->array_len*surface->stride); +// u8 *index_array_ptr=NULL; + +// DVector array_pre_vbo; +// DVector::Write vaw; +// DVector index_array_pre_vbo; +// DVector::Write iaw; + + /* create pointers */ +// array_pre_vbo.resize(surface->array_len*surface->stride); +// vaw = array_pre_vbo.write(); +// array_ptr=vaw.ptr(); + + if (surface->index_array_len) + { +// index_array_pre_vbo.resize(surface->index_array_len*surface->array[VS::ARRAY_INDEX].size); +// iaw = index_array_pre_vbo.write(); +// index_array_ptr=iaw.ptr(); + surface->index_array_local = (u8*) linearAlloc(surface->index_array_len*surface->array[VS::ARRAY_INDEX].size); +// index_array_ptr = (u8*) linearAlloc(surface->index_array_len*surface->array[VS::ARRAY_INDEX].size); + } + + _surface_set_arrays(surface,surface->array_local,surface->index_array_local,p_arrays,true); + + /* create buffers!! */ + + +// glGenBuffers(1,&surface->vertex_id); +// ERR_FAIL_COND(surface->vertex_id==0); +// glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id); +// glBufferData(GL_ARRAY_BUFFER,surface->array_len*surface->stride,array_ptr,GL_STATIC_DRAW); +// glBindBuffer(GL_ARRAY_BUFFER,0); //unbind +// if (surface->index_array_len) { +// +// glGenBuffers(1,&surface->index_id); +// ERR_FAIL_COND(surface->index_id==0); +// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id); +// glBufferData(GL_ELEMENT_ARRAY_BUFFER,index_array_len*surface->array[VS::ARRAY_INDEX].size,index_array_ptr,GL_STATIC_DRAW); +// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); //unbind +// +// } + + mesh->surfaces.push_back(surface); +} + +void Rasterizer3DS::mesh_add_custom_surface(RID p_mesh,const Variant& p_dat) +{ + ERR_EXPLAIN("Rasterizer does not support custom surfaces. Running on wrong platform?"); + ERR_FAIL_V(); +} + +Array Rasterizer3DS::mesh_get_surface_arrays(RID p_mesh,int p_surface) const +{ + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,Array()); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Array() ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, Array() ); + + return surface->data; +} +Array Rasterizer3DS::mesh_get_surface_morph_arrays(RID p_mesh,int p_surface) const +{ + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,Array()); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Array() ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, Array() ); + + return surface->morph_data; +} + + +void Rasterizer3DS::mesh_set_morph_target_count(RID p_mesh,int p_amount) +{ + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + ERR_FAIL_COND( mesh->surfaces.size()!=0 ); + + mesh->morph_target_count=p_amount; +} + +int Rasterizer3DS::mesh_get_morph_target_count(RID p_mesh) const +{ + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,-1); + + return mesh->morph_target_count; +} + +void Rasterizer3DS::mesh_set_morph_target_mode(RID p_mesh,VS::MorphTargetMode p_mode) +{ + ERR_FAIL_INDEX(p_mode,2); + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + + mesh->morph_target_mode=p_mode; +} + +VS::MorphTargetMode Rasterizer3DS::mesh_get_morph_target_mode(RID p_mesh) const +{ + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,VS::MORPH_MODE_NORMALIZED); + + return mesh->morph_target_mode; +} + + + +void Rasterizer3DS::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material,bool p_owned) +{ + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + ERR_FAIL_INDEX(p_surface, mesh->surfaces.size() ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND( !surface); + + if (surface->material_owned && surface->material.is_valid()) + free(surface->material); + + surface->material_owned=p_owned; + surface->material=p_material; +} + +RID Rasterizer3DS::mesh_surface_get_material(RID p_mesh, int p_surface) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,RID()); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), RID() ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, RID() ); + + return surface->material; +} + +int Rasterizer3DS::mesh_surface_get_array_len(RID p_mesh, int p_surface) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,-1); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), -1 ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, -1 ); + + Vector3Array arr = surface->data[VS::ARRAY_VERTEX]; + return arr.size(); + +} + +int Rasterizer3DS::mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,-1); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), -1 ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, -1 ); + + IntArray arr = surface->data[VS::ARRAY_INDEX]; + return arr.size(); + +} +uint32_t Rasterizer3DS::mesh_surface_get_format(RID p_mesh, int p_surface) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,0); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), 0 ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, 0 ); + + return surface->format; +} +VS::PrimitiveType Rasterizer3DS::mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,VS::PRIMITIVE_POINTS); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), VS::PRIMITIVE_POINTS ); + Surface *surface = mesh->surfaces[p_surface]; + ERR_FAIL_COND_V( !surface, VS::PRIMITIVE_POINTS ); + + return surface->primitive; +} + +void Rasterizer3DS::mesh_remove_surface(RID p_mesh,int p_index) { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + ERR_FAIL_INDEX(p_index, mesh->surfaces.size() ); + Surface *surface = mesh->surfaces[p_index]; + ERR_FAIL_COND( !surface); + + memdelete( mesh->surfaces[p_index] ); + mesh->surfaces.remove(p_index); + +} +int Rasterizer3DS::mesh_get_surface_count(RID p_mesh) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,-1); + + return mesh->surfaces.size(); +} + +AABB Rasterizer3DS::mesh_get_aabb(RID p_mesh,RID p_skeleton) const { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,AABB()); + + AABB aabb; + + for (int i=0;isurfaces.size();i++) { + + if (i==0) + aabb=mesh->surfaces[i]->aabb; + else + aabb.merge_with(mesh->surfaces[i]->aabb); + } + + return aabb; +} + +void Rasterizer3DS::mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb) { + + Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND(!mesh); + + mesh->custom_aabb=p_aabb; +} + +AABB Rasterizer3DS::mesh_get_custom_aabb(RID p_mesh) const { + + const Mesh *mesh = mesh_owner.get( p_mesh ); + ERR_FAIL_COND_V(!mesh,AABB()); + + return mesh->custom_aabb; +} + +/* MULTIMESH API */ + +RID Rasterizer3DS::multimesh_create() +{ + print("multimesh_create\n"); + return multimesh_owner.make_rid( memnew( MultiMesh )); +} + +void Rasterizer3DS::multimesh_set_instance_count(RID p_multimesh,int p_count) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh); + + multimesh->elements.clear(); // make sure to delete everything, so it "fails" in all implementations + multimesh->elements.resize(p_count); +} +int Rasterizer3DS::multimesh_get_instance_count(RID p_multimesh) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,-1); + + return multimesh->elements.size(); +} + +void Rasterizer3DS::multimesh_set_mesh(RID p_multimesh,RID p_mesh) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh); + + multimesh->mesh=p_mesh; + +} +void Rasterizer3DS::multimesh_set_aabb(RID p_multimesh,const AABB& p_aabb) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh); + multimesh->aabb=p_aabb; +} +void Rasterizer3DS::multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh); + ERR_FAIL_INDEX(p_index,multimesh->elements.size()); + multimesh->elements[p_index].xform=p_transform; + +} +void Rasterizer3DS::multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh) + ERR_FAIL_INDEX(p_index,multimesh->elements.size()); + multimesh->elements[p_index].color=p_color; + +} + +RID Rasterizer3DS::multimesh_get_mesh(RID p_multimesh) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,RID()); + + return multimesh->mesh; +} +AABB Rasterizer3DS::multimesh_get_aabb(RID p_multimesh) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,AABB()); + + return multimesh->aabb; +} + +Transform Rasterizer3DS::multimesh_instance_get_transform(RID p_multimesh,int p_index) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,Transform()); + + ERR_FAIL_INDEX_V(p_index,multimesh->elements.size(),Transform()); + + return multimesh->elements[p_index].xform; + +} +Color Rasterizer3DS::multimesh_instance_get_color(RID p_multimesh,int p_index) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,Color()); + ERR_FAIL_INDEX_V(p_index,multimesh->elements.size(),Color()); + + return multimesh->elements[p_index].color; +} + +void Rasterizer3DS::multimesh_set_visible_instances(RID p_multimesh,int p_visible) { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND(!multimesh); + multimesh->visible=p_visible; + +} + +int Rasterizer3DS::multimesh_get_visible_instances(RID p_multimesh) const { + + MultiMesh *multimesh = multimesh_owner.get(p_multimesh); + ERR_FAIL_COND_V(!multimesh,-1); + return multimesh->visible; + +} + +/* IMMEDIATE API */ + + +RID Rasterizer3DS::immediate_create() { + + print("immediate_create\n"); + Immediate *im = memnew( Immediate ); + return immediate_owner.make_rid(im); + +} + +void Rasterizer3DS::immediate_begin(RID p_immediate,VS::PrimitiveType p_rimitive,RID p_texture) +{ + print("immediate_begin\n"); +} +void Rasterizer3DS::immediate_vertex(RID p_immediate,const Vector3& p_vertex){ + + +} +void Rasterizer3DS::immediate_normal(RID p_immediate,const Vector3& p_normal){ + + +} +void Rasterizer3DS::immediate_tangent(RID p_immediate,const Plane& p_tangent){ + + +} +void Rasterizer3DS::immediate_color(RID p_immediate,const Color& p_color){ + + +} +void Rasterizer3DS::immediate_uv(RID p_immediate,const Vector2& tex_uv){ + + +} +void Rasterizer3DS::immediate_uv2(RID p_immediate,const Vector2& tex_uv){ + + +} + +void Rasterizer3DS::immediate_end(RID p_immediate){ + + print("immediate_end\n"); +} +void Rasterizer3DS::immediate_clear(RID p_immediate) { + + +} + +AABB Rasterizer3DS::immediate_get_aabb(RID p_immediate) const { + + return AABB(Vector3(-1,-1,-1),Vector3(2,2,2)); +} + +void Rasterizer3DS::immediate_set_material(RID p_immediate,RID p_material) { + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + im->material=p_material; + +} + +RID Rasterizer3DS::immediate_get_material(RID p_immediate) const { + + const Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND_V(!im,RID()); + return im->material; + +} + +/* PARTICLES API */ + +RID Rasterizer3DS::particles_create() +{ + Particles *particles = memnew( Particles ); + ERR_FAIL_COND_V(!particles,RID()); + return particles_owner.make_rid(particles); +} + +void Rasterizer3DS::particles_set_amount(RID p_particles, int p_amount) +{ + ERR_FAIL_COND(p_amount<1); + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.amount=p_amount; +} + +int Rasterizer3DS::particles_get_amount(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.amount; + +} + +void Rasterizer3DS::particles_set_emitting(RID p_particles, bool p_emitting) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.emitting=p_emitting;; + +} +bool Rasterizer3DS::particles_is_emitting(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,false); + return particles->data.emitting; + +} + +void Rasterizer3DS::particles_set_visibility_aabb(RID p_particles, const AABB& p_visibility) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.visibility_aabb=p_visibility; + +} + +void Rasterizer3DS::particles_set_emission_half_extents(RID p_particles, const Vector3& p_half_extents) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + + particles->data.emission_half_extents=p_half_extents; +} +Vector3 Rasterizer3DS::particles_get_emission_half_extents(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,Vector3()); + + return particles->data.emission_half_extents; +} + +void Rasterizer3DS::particles_set_emission_base_velocity(RID p_particles, const Vector3& p_base_velocity) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + + particles->data.emission_base_velocity=p_base_velocity; +} + +Vector3 Rasterizer3DS::particles_get_emission_base_velocity(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,Vector3()); + + return particles->data.emission_base_velocity; +} + + +void Rasterizer3DS::particles_set_emission_points(RID p_particles, const DVector& p_points) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + + particles->data.emission_points=p_points; +} + +DVector Rasterizer3DS::particles_get_emission_points(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,DVector()); + + return particles->data.emission_points; + +} + +void Rasterizer3DS::particles_set_gravity_normal(RID p_particles, const Vector3& p_normal) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + + particles->data.gravity_normal=p_normal; + +} +Vector3 Rasterizer3DS::particles_get_gravity_normal(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,Vector3()); + + return particles->data.gravity_normal; +} + + +AABB Rasterizer3DS::particles_get_visibility_aabb(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,AABB()); + return particles->data.visibility_aabb; + +} + +void Rasterizer3DS::particles_set_variable(RID p_particles, VS::ParticleVariable p_variable,float p_value) { + + ERR_FAIL_INDEX(p_variable,VS::PARTICLE_VAR_MAX); + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.particle_vars[p_variable]=p_value; + +} +float Rasterizer3DS::particles_get_variable(RID p_particles, VS::ParticleVariable p_variable) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.particle_vars[p_variable]; +} + +void Rasterizer3DS::particles_set_randomness(RID p_particles, VS::ParticleVariable p_variable,float p_randomness) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.particle_randomness[p_variable]=p_randomness; + +} +float Rasterizer3DS::particles_get_randomness(RID p_particles, VS::ParticleVariable p_variable) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.particle_randomness[p_variable]; + +} + +void Rasterizer3DS::particles_set_color_phases(RID p_particles, int p_phases) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + ERR_FAIL_COND( p_phases<0 || p_phases>VS::MAX_PARTICLE_COLOR_PHASES ); + particles->data.color_phase_count=p_phases; + +} +int Rasterizer3DS::particles_get_color_phases(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.color_phase_count; +} + + +void Rasterizer3DS::particles_set_color_phase_pos(RID p_particles, int p_phase, float p_pos) { + + ERR_FAIL_INDEX(p_phase, VS::MAX_PARTICLE_COLOR_PHASES); + if (p_pos<0.0) + p_pos=0.0; + if (p_pos>1.0) + p_pos=1.0; + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.color_phases[p_phase].pos=p_pos; + +} +float Rasterizer3DS::particles_get_color_phase_pos(RID p_particles, int p_phase) const { + + ERR_FAIL_INDEX_V(p_phase, VS::MAX_PARTICLE_COLOR_PHASES, -1.0); + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.color_phases[p_phase].pos; + +} + +void Rasterizer3DS::particles_set_color_phase_color(RID p_particles, int p_phase, const Color& p_color) { + + ERR_FAIL_INDEX(p_phase, VS::MAX_PARTICLE_COLOR_PHASES); + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.color_phases[p_phase].color=p_color; + + //update alpha + particles->has_alpha=false; + for(int i=0;idata.color_phases[i].color.a<0.99) + particles->has_alpha=true; + } + +} + +Color Rasterizer3DS::particles_get_color_phase_color(RID p_particles, int p_phase) const { + + ERR_FAIL_INDEX_V(p_phase, VS::MAX_PARTICLE_COLOR_PHASES, Color()); + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,Color()); + return particles->data.color_phases[p_phase].color; + +} + +void Rasterizer3DS::particles_set_attractors(RID p_particles, int p_attractors) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + ERR_FAIL_COND( p_attractors<0 || p_attractors>VisualServer::MAX_PARTICLE_ATTRACTORS ); + particles->data.attractor_count=p_attractors; + +} +int Rasterizer3DS::particles_get_attractors(RID p_particles) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,-1); + return particles->data.attractor_count; +} + +void Rasterizer3DS::particles_set_attractor_pos(RID p_particles, int p_attractor, const Vector3& p_pos) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + ERR_FAIL_INDEX(p_attractor,particles->data.attractor_count); + particles->data.attractors[p_attractor].pos=p_pos;; +} +Vector3 Rasterizer3DS::particles_get_attractor_pos(RID p_particles,int p_attractor) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,Vector3()); + ERR_FAIL_INDEX_V(p_attractor,particles->data.attractor_count,Vector3()); + return particles->data.attractors[p_attractor].pos; +} + +void Rasterizer3DS::particles_set_attractor_strength(RID p_particles, int p_attractor, float p_force) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + ERR_FAIL_INDEX(p_attractor,particles->data.attractor_count); + particles->data.attractors[p_attractor].force=p_force; +} + +float Rasterizer3DS::particles_get_attractor_strength(RID p_particles,int p_attractor) const { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,0); + ERR_FAIL_INDEX_V(p_attractor,particles->data.attractor_count,0); + return particles->data.attractors[p_attractor].force; +} + +void Rasterizer3DS::particles_set_material(RID p_particles, RID p_material,bool p_owned) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + if (particles->material_owned && particles->material.is_valid()) + free(particles->material); + + particles->material_owned=p_owned; + + particles->material=p_material; + +} +RID Rasterizer3DS::particles_get_material(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,RID()); + return particles->material; + +} + +void Rasterizer3DS::particles_set_use_local_coordinates(RID p_particles, bool p_enable) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.local_coordinates=p_enable; + +} + +bool Rasterizer3DS::particles_is_using_local_coordinates(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,false); + return particles->data.local_coordinates; +} +bool Rasterizer3DS::particles_has_height_from_velocity(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,false); + return particles->data.height_from_velocity; +} + +void Rasterizer3DS::particles_set_height_from_velocity(RID p_particles, bool p_enable) { + + Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND(!particles); + particles->data.height_from_velocity=p_enable; + +} + +AABB Rasterizer3DS::particles_get_aabb(RID p_particles) const { + + const Particles* particles = particles_owner.get( p_particles ); + ERR_FAIL_COND_V(!particles,AABB()); + return particles->data.visibility_aabb; +} + +/* SKELETON API */ + +RID Rasterizer3DS::skeleton_create() { + + Skeleton *skeleton = memnew( Skeleton ); + ERR_FAIL_COND_V(!skeleton,RID()); + return skeleton_owner.make_rid( skeleton ); +} +void Rasterizer3DS::skeleton_resize(RID p_skeleton,int p_bones) { + + Skeleton *skeleton = skeleton_owner.get( p_skeleton ); + ERR_FAIL_COND(!skeleton); + if (p_bones == skeleton->bones.size()) { + return; + }; + + skeleton->bones.resize(p_bones); + +} +int Rasterizer3DS::skeleton_get_bone_count(RID p_skeleton) const { + + Skeleton *skeleton = skeleton_owner.get( p_skeleton ); + ERR_FAIL_COND_V(!skeleton, -1); + return skeleton->bones.size(); +} +void Rasterizer3DS::skeleton_bone_set_transform(RID p_skeleton,int p_bone, const Transform& p_transform) { + + Skeleton *skeleton = skeleton_owner.get( p_skeleton ); + ERR_FAIL_COND(!skeleton); + ERR_FAIL_INDEX( p_bone, skeleton->bones.size() ); + + skeleton->bones[p_bone] = p_transform; +} + +Transform Rasterizer3DS::skeleton_bone_get_transform(RID p_skeleton,int p_bone) { + + Skeleton *skeleton = skeleton_owner.get( p_skeleton ); + ERR_FAIL_COND_V(!skeleton, Transform()); + ERR_FAIL_INDEX_V( p_bone, skeleton->bones.size(), Transform() ); + + // something + return skeleton->bones[p_bone]; +} + + +/* LIGHT API */ + +RID Rasterizer3DS::light_create(VS::LightType p_type) { + print("light_create\n"); + Light *light = memnew( Light ); + light->type=p_type; + return light_owner.make_rid(light); +} + +VS::LightType Rasterizer3DS::light_get_type(RID p_light) const { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND_V(!light,VS::LIGHT_OMNI); + return light->type; +} + +void Rasterizer3DS::light_set_color(RID p_light,VS::LightColor p_type, const Color& p_color) { + Light *light = light_owner.get(p_light); + ERR_FAIL_COND(!light); + ERR_FAIL_INDEX( p_type, 3 ); + light->colors[p_type]=p_color; +} +Color Rasterizer3DS::light_get_color(RID p_light,VS::LightColor p_type) const { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND_V(!light, Color()); + ERR_FAIL_INDEX_V( p_type, 3, Color() ); + return light->colors[p_type]; +} + +void Rasterizer3DS::light_set_shadow(RID p_light,bool p_enabled) { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND(!light); + light->shadow_enabled=p_enabled; +} + +bool Rasterizer3DS::light_has_shadow(RID p_light) const { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND_V(!light,false); + return light->shadow_enabled; +} + +void Rasterizer3DS::light_set_volumetric(RID p_light,bool p_enabled) { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND(!light); + light->volumetric_enabled=p_enabled; + +} +bool Rasterizer3DS::light_is_volumetric(RID p_light) const { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND_V(!light,false); + return light->volumetric_enabled; +} + +void Rasterizer3DS::light_set_projector(RID p_light,RID p_texture) { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND(!light); + light->projector=p_texture; +} +RID Rasterizer3DS::light_get_projector(RID p_light) const { + + Light *light = light_owner.get(p_light); + ERR_FAIL_COND_V(!light,RID()); + return light->projector; +} + +void Rasterizer3DS::light_set_var(RID p_light, VS::LightParam p_var, float p_value) { + + Light * light = light_owner.get( p_light ); + ERR_FAIL_COND(!light); + ERR_FAIL_INDEX( p_var, VS::LIGHT_PARAM_MAX ); + + light->vars[p_var]=p_value; +} +float Rasterizer3DS::light_get_var(RID p_light, VS::LightParam p_var) const { + + Light * light = light_owner.get( p_light ); + ERR_FAIL_COND_V(!light,0); + + ERR_FAIL_INDEX_V( p_var, VS::LIGHT_PARAM_MAX,0 ); + + return light->vars[p_var]; +} + +void Rasterizer3DS::light_set_operator(RID p_light,VS::LightOp p_op) { + + Light * light = light_owner.get( p_light ); + ERR_FAIL_COND(!light); + + +}; + +VS::LightOp Rasterizer3DS::light_get_operator(RID p_light) const { + + return VS::LightOp(0); +}; + +void Rasterizer3DS::light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode) { + + +} + +VS::LightOmniShadowMode Rasterizer3DS::light_omni_get_shadow_mode(RID p_light) const{ + + return VS::LightOmniShadowMode(0); +} + +void Rasterizer3DS::light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode) { + + +} + +VS::LightDirectionalShadowMode Rasterizer3DS::light_directional_get_shadow_mode(RID p_light) const { + + return VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; +} + +void Rasterizer3DS::light_directional_set_shadow_param(RID p_light,VS::LightDirectionalShadowParam p_param, float p_value) { + + +} + +float Rasterizer3DS::light_directional_get_shadow_param(RID p_light,VS::LightDirectionalShadowParam p_param) const { + + return 0; +} + + +AABB Rasterizer3DS::light_get_aabb(RID p_light) const { + + Light *light = light_owner.get( p_light ); + ERR_FAIL_COND_V(!light,AABB()); + + switch( light->type ) { + + case VS::LIGHT_SPOT: { + + float len=light->vars[VS::LIGHT_PARAM_RADIUS]; + float size=Math::tan(Math::deg2rad(light->vars[VS::LIGHT_PARAM_SPOT_ANGLE]))*len; + return AABB( Vector3( -size,-size,-len ), Vector3( size*2, size*2, len ) ); + } break; + case VS::LIGHT_OMNI: { + + float r = light->vars[VS::LIGHT_PARAM_RADIUS]; + return AABB( -Vector3(r,r,r), Vector3(r,r,r)*2 ); + } break; + case VS::LIGHT_DIRECTIONAL: { + + return AABB(); + } break; + default: {} + } + + ERR_FAIL_V( AABB() ); +} + + +RID Rasterizer3DS::light_instance_create(RID p_light) { + + Light *light = light_owner.get( p_light ); + ERR_FAIL_COND_V(!light, RID()); + + LightInstance *light_instance = memnew( LightInstance ); + + light_instance->light=p_light; + light_instance->base=light; + + return light_instance_owner.make_rid( light_instance ); +} +void Rasterizer3DS::light_instance_set_transform(RID p_light_instance,const Transform& p_transform) { + + LightInstance *lighti = light_instance_owner.get( p_light_instance ); + ERR_FAIL_COND(!lighti); + lighti->transform=p_transform; +} + +bool Rasterizer3DS::light_instance_has_shadow(RID p_light_instance) const { + + return false; + +} + + +bool Rasterizer3DS::light_instance_assign_shadow(RID p_light_instance) { + + return false; + +} + + +Rasterizer::ShadowType Rasterizer3DS::light_instance_get_shadow_type(RID p_light_instance) const { + + LightInstance *lighti = light_instance_owner.get( p_light_instance ); + ERR_FAIL_COND_V(!lighti,Rasterizer::SHADOW_NONE); + + switch(lighti->base->type) { + + case VS::LIGHT_DIRECTIONAL: return SHADOW_PSM; break; + case VS::LIGHT_OMNI: return SHADOW_DUAL_PARABOLOID; break; + case VS::LIGHT_SPOT: return SHADOW_SIMPLE; break; + } + + return Rasterizer::SHADOW_NONE; +} + +Rasterizer::ShadowType Rasterizer3DS::light_instance_get_shadow_type(RID p_light_instance,bool p_far) const { + + return SHADOW_NONE; +} +void Rasterizer3DS::light_instance_set_shadow_transform(RID p_light_instance, int p_index, const CameraMatrix& p_camera, const Transform& p_transform, float p_split_near,float p_split_far) { + + +} + +int Rasterizer3DS::light_instance_get_shadow_passes(RID p_light_instance) const { + + return 0; +} + +bool Rasterizer3DS::light_instance_get_pssm_shadow_overlap(RID p_light_instance) const { + + return false; +} + + +void Rasterizer3DS::light_instance_set_custom_transform(RID p_light_instance, int p_index, const CameraMatrix& p_camera, const Transform& p_transform, float p_split_near,float p_split_far) { + + LightInstance *lighti = light_instance_owner.get( p_light_instance ); + ERR_FAIL_COND(!lighti); + + ERR_FAIL_COND(lighti->base->type!=VS::LIGHT_DIRECTIONAL); + ERR_FAIL_INDEX(p_index,1); + + lighti->custom_projection=p_camera; + lighti->custom_transform=p_transform; + +} +void Rasterizer3DS::shadow_clear_near() { + + +} + +bool Rasterizer3DS::shadow_allocate_near(RID p_light) { + + return false; +} + +bool Rasterizer3DS::shadow_allocate_far(RID p_light) { + + return false; +} + +/* PARTICLES INSTANCE */ + +RID Rasterizer3DS::particles_instance_create(RID p_particles) { + + ERR_FAIL_COND_V(!particles_owner.owns(p_particles),RID()); + ParticlesInstance *particles_instance = memnew( ParticlesInstance ); + ERR_FAIL_COND_V(!particles_instance, RID() ); + particles_instance->particles=p_particles; + return particles_instance_owner.make_rid(particles_instance); +} + +void Rasterizer3DS::particles_instance_set_transform(RID p_particles_instance,const Transform& p_transform) { + + ParticlesInstance *particles_instance=particles_instance_owner.get(p_particles_instance); + ERR_FAIL_COND(!particles_instance); + particles_instance->transform=p_transform; +} + + +/* RENDER API */ +/* all calls (inside begin/end shadow) are always warranted to be in the following order: */ + + +RID Rasterizer3DS::viewport_data_create() +{ + print("viewport_data_create\n"); + return RID(); +} + +RID Rasterizer3DS::render_target_create() +{ + print("render_target_create\n"); + RenderTarget* rt = memnew(RenderTarget); + Texture *texture = memnew(Texture); + + rt->target = C3D_RenderTargetCreate(480, 800, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); + C3D_RenderTargetSetOutput(rt->target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); + C3D_RenderTargetClear(rt->target,C3D_CLEAR_ALL,CLEAR_COLOR,0); + rt->texture_ptr = texture; + rt->texture = texture_owner.make_rid( texture ); + + return render_target_owner.make_rid( rt ); +} +void Rasterizer3DS::render_target_set_size(RID p_render_target, int p_width, int p_height) +{ + RenderTarget* rt = render_target_owner.get( p_render_target ); + +} +RID Rasterizer3DS::render_target_get_texture(RID p_render_target) const +{ + print("render_target_get_texture\n"); + const RenderTarget *rt = render_target_owner.get(p_render_target); + ERR_FAIL_COND_V(!rt,RID()); + return rt->texture; +} +bool Rasterizer3DS::render_target_renedered_in_frame(RID p_render_target) +{ + RenderTarget *rt = render_target_owner.get(p_render_target); + ERR_FAIL_COND_V(!rt,false); +// return rt->last_pass==frame; + return false; +} + + +void Rasterizer3DS::begin_frame() +{ + print("begin_frame\n"); + draw_next_frame = false; + + float time = (OS::get_singleton()->get_ticks_usec()/1000); // get msec + time/=1000.0; // make secs + if (frame != 0) { + time_delta = time_scale * (time - last_time); + } else { + time_delta = 0.0f; + } + scaled_time += time_delta; + last_time=time; + frame++; + C3D_FrameBegin(0); +} + +void Rasterizer3DS::capture_viewport(Image* r_capture) { + + +} + + +void Rasterizer3DS::clear_viewport(const Color& p_color) +{ + print("clear_viewport\n"); + RenderTarget* rt = current_rt ? current_rt : base_framebuffer; + u32 c = (u8)(p_color.r*255); + c <<= 8; + c |= (u8)(p_color.g*255); + c <<= 8; + c |= (u8)(p_color.b*255); + c <<= 8; + c |= (u8)(p_color.a*255); + C3D_RenderTargetClear(rt->target,C3D_CLEAR_ALL,c,0); +}; + +void Rasterizer3DS::set_viewport(const VS::ViewportRect& p_viewport) +{ + print("set_viewport %d %d %d %d\n", p_viewport.x, p_viewport.y, p_viewport.width, p_viewport.height); + u32 top = p_viewport.height - p_viewport.y; + //C3D_SetViewport(top, p_viewport.x, p_viewport.height, p_viewport.width); + C3D_SetViewport(0, 0, p_viewport.height, p_viewport.width); +} + +void Rasterizer3DS::set_time_scale(float p_scale) +{ + time_scale = p_scale; +} +void Rasterizer3DS::set_render_target(RID p_render_target, bool p_transparent_bg, bool p_vflip) +{ + print("set_render_target\n"); + current_rt_vflip=p_vflip; + + if (p_render_target.is_valid()) + { + RenderTarget *rt = render_target_owner.get(p_render_target); + ERR_FAIL_COND(!rt); + ERR_FAIL_COND(!rt->target); + //C3D_RenderTargetSetOutput(rt->target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); + C3D_SetFrameBuf(&rt->target->frameBuf); + //C3D_RenderBufBind(&rt->target->renderBuf); + current_rt=rt; + current_rt_transparent=p_transparent_bg; + } + else + { + print("null target\n"); + current_rt = NULL; + current_rt_transparent = false; + C3D_SetFrameBuf(&base_framebuffer->target->frameBuf); + //C3D_RenderTargetSetOutput(base_framebuffer->target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); + //C3D_RenderBufBind(&base_framebuffer->target->renderBuf); + } +} + + +void Rasterizer3DS::begin_scene(RID p_viewport_data,RID p_env,VS::ScenarioDebugMode p_debug) +{ + print("begin_scene\n"); + opaque_render_list.clear(); + alpha_render_list.clear(); + + RenderTarget* rt = current_rt ? current_rt : base_framebuffer; + + current_env = p_env.is_valid() ? environment_owner.get(p_env) : NULL; +// current_vd=viewport_data_owner.get(p_viewport_data); + + C3D_TexEnv* env = C3D_GetTexEnv(0); + C3D_TexEnvSrc(env, C3D_Both, GPU_FRAGMENT_PRIMARY_COLOR, GPU_FRAGMENT_SECONDARY_COLOR); + C3D_TexEnvOpRgb(env, GPU_TEVOP_RGB_SRC_COLOR); + C3D_TexEnvOpAlpha(env,GPU_TEVOP_A_SRC_ALPHA); + C3D_TexEnvFunc(env, C3D_Both, GPU_ADD); + + C3D_TexBind(0, NULL); + + C3D_BindProgram(&scene_shader->program); + _set_uniform(scene_shader->location_modelview, Matrix32()); + _set_uniform(scene_shader->location_extra, Matrix32()); +}; + +void Rasterizer3DS::begin_shadow_map( RID p_light_instance, int p_shadow_pass ) { + +} + +void Rasterizer3DS::set_camera(const Transform& p_world, const CameraMatrix& p_projection) +{ + + + print("set_camera\n"); + camera_transform=p_world; +// if (current_rt && current_rt_vflip) { + if (current_rt_vflip) { +// m[4] = -1; +// camera_transform.basis.set_axis(1,-camera_transform.basis.get_axis(1)); + } +// camera_transform.basis.set_axis(0,-camera_transform.basis.get_axis(0)); + + camera_transform_inverse=camera_transform.inverse(); + camera_projection = p_projection; +// camera_projection.get_fov() +// camera_projection=*reinterpret_cast(m) * p_projection; +// camera_projection = camera_projection * m; +// camera_projection.invert(); + camera_plane = Plane( camera_transform.origin, -camera_transform.basis.get_axis(2) ); + camera_z_near=camera_projection.get_z_near(); + camera_z_far=camera_projection.get_z_far(); + camera_projection.get_viewport_size(camera_vp_size.x,camera_vp_size.y); + // camera_ortho=p_ortho_hint; + + print("z-near:%f z-far:%f\n", camera_z_near, camera_z_far); + print("x:%f y:%f\n", camera_vp_size.x,camera_vp_size.y); + +// for (int i = 0; i < 4; ++i) +// print("%f %f %f %f\n", m[i*4], m[i*4+1], m[i*4+2], m[i*4+3]); + + _set_uniform(scene_shader->location_modelview, Matrix32()); +// _set_uniform(scene_shader->location_worldTransform, Matrix32()); + _set_uniform(scene_shader->location_worldTransform, camera_transform_inverse); + _set_uniform(scene_shader->location_projection, camera_projection); + +// C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, scene_shader->location_projection, &mtx); +} + +void Rasterizer3DS::add_light( RID p_light_instance ) +{ + // ERR_FAIL_COND( light_instance_count >= MAX_SCENE_LIGHTS ); + + LightInstance *li = light_instance_owner.get(p_light_instance); + ERR_FAIL_COND(!li); + + // light_instances[light_instance_count++]=li; + C3D_LightInit(&li->base->light, &lightEnv); +} + +void Rasterizer3DS::add_immediate( const RID& p_immediate, const InstanceData *p_data) +{ + print("add_immediate\n"); +} + + +void Rasterizer3DS::add_mesh( const RID& p_mesh, const InstanceData *p_data) { + + Mesh *mesh = mesh_owner.get(p_mesh); + ERR_FAIL_COND(!mesh); + + int ssize = mesh->surfaces.size(); + + for (int i=0;isurfaces[i]; + _add_geometry(s,p_data,s,NULL); + } + + mesh->last_pass=frame; + +} + +void Rasterizer3DS::add_multimesh( const RID& p_multimesh, const InstanceData *p_data) +{ + print("add_multimesh\n"); +} + +void Rasterizer3DS::add_particles( const RID& p_particle_instance, const InstanceData *p_data) +{ + ParticlesInstance *particles_instance = particles_instance_owner.get(p_particle_instance); + ERR_FAIL_COND(!particles_instance); + Particles *p=particles_owner.get( particles_instance->particles ); + ERR_FAIL_COND(!p); + + _add_geometry(p, p_data, p, particles_instance); +// draw_next_frame=true; +} + + + +void Rasterizer3DS::end_scene() +{ + print("end_scene\n"); + +// opaque_render_list.sort_mat_light_type_flags(); + _render_list_forward(&opaque_render_list, camera_transform, camera_transform_inverse,camera_projection,false,fragment_lighting); + +// alpha_render_list.sort_z(); +// _render_list_forward(&alpha_render_list, camera_transform, camera_transform_inverse,camera_projection,false,fragment_lighting,true); + +} +void Rasterizer3DS::end_shadow_map() { + +} + + +void Rasterizer3DS::end_frame() +{ + C3D_FrameEnd(GX_CMDLIST_UPDATE_GAS_ACC); + + print("end_frame %d %f\n", vertexArrays.size(), C3D_GetCmdBufUsage()); + + RenderTarget* rt = current_rt ? current_rt : base_framebuffer; + C3D_FrameBufTransfer(&rt->target->frameBuf,rt->target->screen,rt->target->side,rt->target->transferFlags); + VertexArray **varray = vertexArrays.ptr(); + for (int i = 0; i < vertexArrays.size(); ++i) + memdelete(*varray++); + vertexArrays.clear(); + + // OS::get_singleton()->swap_buffers(); + gfxSwapBuffersGpu(); + // if (use_vsync) + gspWaitForVBlank(); +} + +void Rasterizer3DS::flush_frame() +{ +} + +RID Rasterizer3DS::canvas_light_occluder_create() +{ + CanvasOccluder *co = memnew( CanvasOccluder ); + co->index_id=0; + co->vertex_id=0; + co->len=0; + + return canvas_occluder_owner.make_rid(co); +} + +void Rasterizer3DS::canvas_light_occluder_set_polylines(RID p_occluder, const DVector& p_lines) +{ + CanvasOccluder *co = canvas_occluder_owner.get(p_occluder); + ERR_FAIL_COND(!co); + return; + + co->lines=p_lines; + + if (p_lines.size()!=co->len) { + +// if (co->index_id) +// glDeleteBuffers(1,&co->index_id); +// if (co->vertex_id) +// glDeleteBuffers(1,&co->vertex_id); + + co->index_id=0; + co->vertex_id=0; + co->len=0; + + } + + if (p_lines.size()) { + + + + DVector geometry; + DVector indices; + int lc = p_lines.size(); + + geometry.resize(lc*6); + indices.resize(lc*3); + + DVector::Write vw=geometry.write(); + DVector::Write iw=indices.write(); + + + DVector::Read lr=p_lines.read(); + + const int POLY_HEIGHT = 16384; + + for(int i=0;ivertex_id) { +// glGenBuffers(1,&co->vertex_id); +// glBindBuffer(GL_ARRAY_BUFFER,co->vertex_id); +// glBufferData(GL_ARRAY_BUFFER,lc*6*sizeof(real_t),vw.ptr(),GL_STATIC_DRAW); + } else { + +// glBindBuffer(GL_ARRAY_BUFFER,co->vertex_id); +// glBufferSubData(GL_ARRAY_BUFFER,0,lc*6*sizeof(real_t),vw.ptr()); + + } + +// glBindBuffer(GL_ARRAY_BUFFER,0); //unbind + + if (!co->index_id) { + +// glGenBuffers(1,&co->index_id); +// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,co->index_id); +// glBufferData(GL_ELEMENT_ARRAY_BUFFER,lc*3*sizeof(uint16_t),iw.ptr(),GL_STATIC_DRAW); + } else { + + +// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,co->index_id); +// glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,0,lc*3*sizeof(uint16_t),iw.ptr()); + } + +// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); //unbind + + co->len=lc; + } +} + +RID Rasterizer3DS::canvas_light_shadow_buffer_create(int p_width) +{ + return RID(); + CanvasLightShadow *cls = memnew( CanvasLightShadow ); + if (p_width>1024) + p_width=1024; + + cls->size=p_width; + cls->height=16; + +/* + glActiveTexture(GL_TEXTURE0); + + glGenFramebuffers(1, &cls->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); + + // Create a render buffer + glGenRenderbuffers(1, &cls->rbo); + glBindRenderbuffer(GL_RENDERBUFFER, cls->rbo); + + // Create a texture for storing the depth + glGenTextures(1, &cls->depth); + glBindTexture(GL_TEXTURE_2D, cls->depth); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + // Remove artifact on the edges of the shadowmap + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +*/ + cls->renderTarget = C3D_RenderTargetCreate(480, 800, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); + C3D_RenderTargetSetOutput(cls->renderTarget, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); + C3D_RenderTargetClear(cls->renderTarget,C3D_CLEAR_ALL,C3D_CLEAR_COLOR,0); + +// ERR_FAIL_COND(!C3D_TexInit(&cls->texture, w, h, GPU_RGBA8)); + + +/* + //print_line("ERROR? "+itos(glGetError())); + if ( read_depth_supported ) { + + // We'll use a depth texture to store the depths in the shadow map + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, cls->size, cls->height, 0, + GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + +#ifdef GLEW_ENABLED + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +#endif + + // Attach the depth texture to FBO depth attachment point + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, cls->depth, 0); + +#ifdef GLEW_ENABLED + glDrawBuffer(GL_NONE); +#endif + + } else { + // We'll use a RGBA texture into which we pack the depth info + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cls->size, cls->height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + // Attach the RGBA texture to FBO color attachment point + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, cls->depth, 0); + cls->rgba=cls->depth; + + // Allocate 16-bit depth buffer + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, cls->size, cls->height); + + // Attach the render buffer as depth buffer - will be ignored + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, cls->rbo); + + + } + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + //printf("errnum: %x\n",status); +#ifdef GLEW_ENABLED + if (read_depth_supported) { + //glDrawBuffer(GL_BACK); + } +#endif + glBindFramebuffer(GL_FRAMEBUFFER, base_framebuffer); + DEBUG_TEST_ERROR("2D Shadow Buffer Init"); + ERR_FAIL_COND_V( status != GL_FRAMEBUFFER_COMPLETE, RID() ); + +#ifdef GLEW_ENABLED + if (read_depth_supported) { + //glDrawBuffer(GL_BACK); + } +#endif +*/ + return canvas_light_shadow_owner.make_rid(cls); +} + + + +/* CANVAS API */ + + +void Rasterizer3DS::begin_canvas_bg() +{ + print("begin_canvas_bg\n"); +} +void Rasterizer3DS::canvas_begin() +{ + print("canvas_begin"); + + C3D_Mtx projection; + Mtx_OrthoTilt(&projection, 0.0, 800.0, 480.0, 0.0, 0.0, 1.0, true); + + C3D_BindProgram(&canvas_shader->program); + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, canvas_shader->location_projection, &projection); + + _set_uniform(canvas_shader->location_modelview, Matrix32()); + _set_uniform(canvas_shader->location_extra, Matrix32()); + + C3D_AttrInfo* attrInfo = C3D_GetAttrInfo(); + AttrInfo_Init(attrInfo); + AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position + AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2); // v1=texcoord + AttrInfo_AddFixed(attrInfo, 2); // v2=color + + canvas_opacity = 1.0; + + canvas_blend_mode = VS::MATERIAL_BLEND_MODE_MIX; + C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA); + + print(" %f\n", C3D_GetCmdBufUsage()); +} +void Rasterizer3DS::canvas_disable_blending() +{ + print("canvas_disable_blending\n"); + C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA); +} + +void Rasterizer3DS::canvas_set_opacity(float p_opacity) +{ + canvas_opacity = p_opacity; +} + +void Rasterizer3DS::canvas_set_blend_mode(VS::MaterialBlendMode p_mode) +{ + if (p_mode==canvas_blend_mode) + return; + + switch(p_mode) + { + case VS::MATERIAL_BLEND_MODE_MIX: { + if (current_rt && current_rt_transparent) { + C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + } + else { + C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA); + } + + } break; + case VS::MATERIAL_BLEND_MODE_ADD: { + + C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE, GPU_SRC_ALPHA, GPU_ONE); + + } break; + case VS::MATERIAL_BLEND_MODE_SUB: { + C3D_AlphaBlend(GPU_BLEND_REVERSE_SUBTRACT, GPU_BLEND_REVERSE_SUBTRACT, GPU_SRC_ALPHA, GPU_ONE, GPU_SRC_ALPHA, GPU_ONE); + } break; + case VS::MATERIAL_BLEND_MODE_MUL: { + C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_DST_COLOR, GPU_ZERO, GPU_DST_COLOR, GPU_ZERO); + } break; + case VS::MATERIAL_BLEND_MODE_PREMULT_ALPHA: { + C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + } break; + } + + canvas_blend_mode=p_mode; +} + +void Rasterizer3DS::canvas_begin_rect(const Matrix32& p_transform) +{ + _set_uniform(canvas_shader->location_modelview, p_transform); + _set_uniform(canvas_shader->location_extra, Matrix32()); +// canvas_transform = p_transform; +} + +void Rasterizer3DS::canvas_set_clip(bool p_clip, const Rect2& p_rect) { + + + + +} + +void Rasterizer3DS::canvas_end_rect() +{ + print("canvas_end_rect\n"); +} + +void Rasterizer3DS::canvas_draw_line(const Point2& p_from, const Point2& p_to, const Color& p_color, float p_width) +{ + print("canvas_draw_line\n"); +} + +void Rasterizer3DS::canvas_draw_rect(const Rect2& p_rect, int p_flags, const Rect2& p_source,RID p_texture,const Color& p_modulate) +{ +// print("canvas_draw_rect %.1f %.1f %.1f %.1f\n", p_rect.pos.x, p_rect.pos.y, p_rect.size.width, p_rect.size.height); + + // Set the fixed attribute (color) + C3D_FixedAttribSet(2, p_modulate.r, p_modulate.g, p_modulate.b, p_modulate.a * canvas_opacity); +// C3D_FixedAttribSet(2, 1.f, 1.f, 1.f, 1.f); + C3D_TexEnv* env = C3D_GetTexEnv(0); + + + if (p_texture.is_valid()) + { + Texture* texture = texture_owner.get(p_texture); +// ERR_FAIL_COND(!texture); + + if (p_flags & CANVAS_RECT_TILE && !(texture->flags & VS::TEXTURE_FLAG_REPEAT)) + { + + } + + C3D_TexBind(0, &texture->tex); + + C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR); + C3D_TexEnvOpRgb(env, GPU_TEVOP_RGB_SRC_COLOR); + C3D_TexEnvOpAlpha(env,GPU_TEVOP_A_SRC_ALPHA); + C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE); + + if (!(p_flags&CANVAS_RECT_REGION)) { +// // + Rect2 region = Rect2(0,0,texture->tex.width,texture->tex.height); + _draw_textured_quad(p_rect,region,region.size,p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V); + + } else { + + _draw_textured_quad(p_rect, p_source, Size2(texture->tex.width,texture->tex.height),p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V); + + } + } + else + { + C3D_TexBind(0, NULL); + + C3D_TexEnvSrc(env, C3D_Both, GPU_PRIMARY_COLOR); + C3D_TexEnvOpRgb(env, GPU_TEVOP_RGB_SRC_COLOR); + C3D_TexEnvOpAlpha(env,GPU_TEVOP_A_SRC_ALPHA); + C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE); + + _draw_quad(p_rect); + } +} +void Rasterizer3DS::canvas_draw_style_box(const Rect2& p_rect, RID p_texture,const float *p_margin, bool p_draw_center,const Color& p_modulate) +{ + print("canvas_draw_style_box\n"); + +// Color m = p_modulate; +// m.a*=canvas_opacity; +// _set_color_attrib(m); + C3D_FixedAttribSet(2, p_modulate.r, p_modulate.g, p_modulate.b, p_modulate.a * canvas_opacity); + + Texture* texture=_bind_texture(p_texture); + ERR_FAIL_COND(!texture); + + Rect2 region = p_rect; + + // Rect2 region( p_rect.pos+Point2( p_margin[MARGIN_LEFT], p_margin[MARGIN_TOP]), Size2( p_rect.size.width - p_margin[MARGIN_LEFT] - p_margin[MARGIN_RIGHT], p_rect.size.height - p_margin[MARGIN_TOP] - p_margin[MARGIN_BOTTOM] )); + + // Rect2 src_center( Point2( p_margin[MARGIN_LEFT], p_margin[MARGIN_TOP]), Size2( texture->width - p_margin[MARGIN_LEFT] - p_margin[MARGIN_RIGHT], texture->height - p_margin[MARGIN_TOP] - p_margin[MARGIN_BOTTOM] )); + + if (region.size.width <= 0 ) + region.size.width = texture->width; + if (region.size.height <= 0) + region.size.height = texture->height; + /* CORNERS */ + _draw_textured_quad( // top left + Rect2( p_rect.pos, Size2(p_margin[MARGIN_LEFT],p_margin[MARGIN_TOP])), + Rect2( region.pos, Size2(p_margin[MARGIN_LEFT],p_margin[MARGIN_TOP])), + Size2( texture->width, texture->height ) ); + + _draw_textured_quad( // top right + Rect2( Point2( p_rect.pos.x + p_rect.size.width - p_margin[MARGIN_RIGHT], p_rect.pos.y), Size2(p_margin[MARGIN_RIGHT],p_margin[MARGIN_TOP])), + Rect2( Point2(region.pos.x+region.size.width-p_margin[MARGIN_RIGHT], region.pos.y), Size2(p_margin[MARGIN_RIGHT],p_margin[MARGIN_TOP])), + Size2( texture->width, texture->height ) ); + + + _draw_textured_quad( // bottom left + Rect2( Point2(p_rect.pos.x,p_rect.pos.y + p_rect.size.height - p_margin[MARGIN_BOTTOM]), Size2(p_margin[MARGIN_LEFT],p_margin[MARGIN_BOTTOM])), + Rect2( Point2(region.pos.x, region.pos.y+region.size.height-p_margin[MARGIN_BOTTOM]), Size2(p_margin[MARGIN_LEFT],p_margin[MARGIN_BOTTOM])), + Size2( texture->width, texture->height ) ); + + _draw_textured_quad( // bottom right + Rect2( Point2( p_rect.pos.x + p_rect.size.width - p_margin[MARGIN_RIGHT], p_rect.pos.y + p_rect.size.height - p_margin[MARGIN_BOTTOM]), Size2(p_margin[MARGIN_RIGHT],p_margin[MARGIN_BOTTOM])), + Rect2( Point2(region.pos.x+region.size.width-p_margin[MARGIN_RIGHT], region.pos.y+region.size.height-p_margin[MARGIN_BOTTOM]), Size2(p_margin[MARGIN_RIGHT],p_margin[MARGIN_BOTTOM])), + Size2( texture->width, texture->height ) ); + + Rect2 rect_center( p_rect.pos+Point2( p_margin[MARGIN_LEFT], p_margin[MARGIN_TOP]), Size2( p_rect.size.width - p_margin[MARGIN_LEFT] - p_margin[MARGIN_RIGHT], p_rect.size.height - p_margin[MARGIN_TOP] - p_margin[MARGIN_BOTTOM] )); + + Rect2 src_center( Point2(region.pos.x+p_margin[MARGIN_LEFT], region.pos.y+p_margin[MARGIN_TOP]), Size2(region.size.width - p_margin[MARGIN_LEFT] - p_margin[MARGIN_RIGHT], region.size.height - p_margin[MARGIN_TOP] - p_margin[MARGIN_BOTTOM] )); + + + _draw_textured_quad( // top + Rect2( Point2(rect_center.pos.x,p_rect.pos.y),Size2(rect_center.size.width,p_margin[MARGIN_TOP])), + Rect2( Point2(src_center.pos.x,region.pos.y), Size2(src_center.size.width,p_margin[MARGIN_TOP])), + Size2( texture->width, texture->height ) ); + + _draw_textured_quad( // bottom + Rect2( Point2(rect_center.pos.x,rect_center.pos.y+rect_center.size.height),Size2(rect_center.size.width,p_margin[MARGIN_BOTTOM])), + Rect2( Point2(src_center.pos.x,src_center.pos.y+src_center.size.height), Size2(src_center.size.width,p_margin[MARGIN_BOTTOM])), + Size2( texture->width, texture->height ) ); + + _draw_textured_quad( // left + Rect2( Point2(p_rect.pos.x,rect_center.pos.y),Size2(p_margin[MARGIN_LEFT],rect_center.size.height)), + Rect2( Point2(region.pos.x,region.pos.y+p_margin[MARGIN_TOP]), Size2(p_margin[MARGIN_LEFT],src_center.size.height)), + Size2( texture->width, texture->height ) ); + + _draw_textured_quad( // right + Rect2( Point2(rect_center.pos.x+rect_center.size.width,rect_center.pos.y),Size2(p_margin[MARGIN_RIGHT],rect_center.size.height)), + Rect2( Point2(src_center.pos.x+src_center.size.width,region.pos.y+p_margin[MARGIN_TOP]), Size2(p_margin[MARGIN_RIGHT],src_center.size.height)), + Size2( texture->width, texture->height ) ); + + if (p_draw_center) { + _draw_textured_quad( + rect_center, + src_center, + Size2( texture->width, texture->height )); + } + + _rinfo.ci_draw_commands++; +} +void Rasterizer3DS::canvas_draw_primitive(const Vector& p_points, const Vector& p_colors,const Vector& p_uvs, RID p_texture,float p_width) +{ + print("canvas_draw_primitive\n"); +} + + +void Rasterizer3DS::canvas_draw_polygon(int p_vertex_count, const int* p_indices, const Vector2* p_vertices, const Vector2* p_uvs, const Color* p_colors,const RID& p_texture,bool p_singlecolor) +{ + print("canvas_draw_polygon\n"); +} + +Rasterizer3DS::Texture* Rasterizer3DS::_bind_texture(const RID& p_texture) +{ + if (p_texture.is_valid()) + { + Texture*texture=texture_owner.get(p_texture); + C3D_TexBind(0, &texture->tex); + return texture; + } + + C3D_TexBind(0, NULL); + return NULL; +} + +void Rasterizer3DS::_set_uniform(int uniform_location, const Matrix32& p_transform) +{ + const Matrix32& tr = p_transform; + + C3D_Mtx mtx; +// float matrix[16] = { /* build a 16x16 matrix */ +// tr.elements[2][0], tr.elements[2][1], 0, 1, +// 0, 0, 1, 0, +// tr.elements[1][0], tr.elements[1][1], 0, 0, +// tr.elements[0][0], tr.elements[0][1], 0, 0, +// }; + +// float m[16]={ /* build a 16x16 matrix */ +// tr.elements[0][0], tr.elements[0][1], 0, 0, +// tr.elements[1][0], tr.elements[1][1], 0, 0, +// 0, 0, 1, 0, +// tr.elements[2][0], tr.elements[2][1], 0, 1 +// }; + + float matrix[16] = { /* build a 16x16 matrix */ + tr.elements[2][0], 0, tr.elements[1][0], tr.elements[0][0], + tr.elements[2][1], 0, tr.elements[1][1], tr.elements[0][1], + 0, 1, 0, 0, + 1, 0, 0, 0, + }; + + memcpy(mtx.m, matrix, sizeof(matrix)); + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uniform_location, &mtx); +} + +void Rasterizer3DS::_set_uniform(int uniform_location, const Transform& p_transform) +{ + const Transform& tr = p_transform; + + C3D_Mtx mtx; +// float matrix[16]={ /* build a 16x16 matrix */ +// tr.basis.elements[0][0], tr.basis.elements[1][0], tr.basis.elements[2][0], 0, +// tr.basis.elements[0][1], tr.basis.elements[1][1], tr.basis.elements[2][1], 0, +// tr.basis.elements[0][2], tr.basis.elements[1][2], tr.basis.elements[2][2], 0, +// tr.origin.x, tr.origin.y, tr.origin.z, 1 +// }; + float matrix[16]={ /* build a 16x16 matrix */ + tr.origin.x, tr.basis.elements[0][2], tr.basis.elements[0][1], tr.basis.elements[0][0], + tr.origin.y, tr.basis.elements[1][2], tr.basis.elements[1][1], tr.basis.elements[1][0], + tr.origin.z, tr.basis.elements[2][2], tr.basis.elements[2][1], tr.basis.elements[2][0], + 1, 0, 0, 0, + }; + + memcpy(mtx.m, matrix, sizeof(matrix)); + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uniform_location, &mtx); +} + + +void Rasterizer3DS::_set_uniform(int uniform_location, const Color& p_color) +{/* + const Color& c = p_color; + + C3D_Mtx mat = {{ + { { c.r, c.g, c.b, 1.0f } }, // Ambient + { { c.r, c.g, c.b, 1.0f } }, // Diffuse + { { 1.0f, 0.0f, 0.0f, 1.0f } }, // Specular + { { 1.0f, 0.0f, 0.0f, 1.0f } }, // Emission + }};*/ + /* + C3D_Mtx material = +{ + { + { { 1.0f, 0.2f, 1.0f, 1.0f } }, // Ambient + { { 1.0f, 0.4f, 0.4f, 1.0f } }, // Diffuse + { { 1.0f, 0.8f, 0.8f, 1.0f } }, // Specular + { { 1.0f, 0.0f, 0.0f, 1.0f } }, // Emission + } +};*/ + // memcpy(mtx.m, matrix, sizeof(matrix)); + // C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uniform_location, &mat); + + +} + +void Rasterizer3DS::_set_uniform(int uniform_location, const CameraMatrix& p_matrix) +{ + // Swap X/Y axis due to 3DS screens being sideways + // and adjust clipping range from [-1, 1] to [-1, 0] + float m[16] = { + 0, -1, 0, 0, + 1, 0, 0, 0, + 0, 0, 0.5, 0, +// 0, 0, 1, 0, + 0, 0, -0.5, 1, + }; + + CameraMatrix p = *reinterpret_cast(m) * p_matrix; + + C3D_Mtx mtx; + float *to = mtx.m; + const float *from = reinterpret_cast(p.matrix); +// for (int i = 0; i < 4; ++i) +// { +// mtx.r[i].x = *from++; +// mtx.r[i].y = *from++; +// mtx.r[i].z = *from++; +// mtx.r[i].w = *from++; +// } + + to[0] = from[12]; + to[1] = from[8]; + to[2] = from[4]; + to[3] = from[0]; + to[4] = from[13]; + to[5] = from[9]; + to[6] = from[5]; + to[7] = from[1]; + to[8] = from[14]; + to[9] = from[10]; + to[10] = from[6]; + to[11] = from[2]; + to[12] = from[15]; + to[13] = from[11]; + to[14] = from[7]; + to[15] = from[3]; + +// for (int i = 0; i < 4; ++i) +// print("%f %f %f %f\n", to[i*4], to[i*4+1], to[i*4+2], to[i*4+3]); + + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uniform_location, &mtx); +} + +void Rasterizer3DS::canvas_set_transform(const Matrix32& p_transform) +{ + _set_uniform(canvas_shader->location_extra, p_transform); +} + +static void _set_scissor(int x, int y, int w, int h) +{ + print("set_scissor %d %d %d %d\n", x, y, w, h); + // Keep in mind the sideway 3ds screen, so it seems screwy + int bottom = 400 - x; + int top = 240 - y; + int left = top - h; + int right = bottom - w; + if (bottom < 0) bottom = 0; + if (top < 0) top = 0; + if (left < 0) left = 0; + if (right < 0) right = 0; + C3D_SetScissor(GPU_SCISSOR_NORMAL, left, right, top, bottom); +// C3D_SetScissor(GPU_SCISSOR_NORMAL, 240 - (y + h), 400 - (x + w), 240 - y, 400 - x); +} +#if 0 + +void Rasterizer3DS::_set_canvas_scissor(CanvasItem* p_item) +{ + int x, y, w, h; + + if (current_rt) { + x = p_item->final_clip_rect.pos.x; + y = p_item->final_clip_rect.pos.y; + w = p_item->final_clip_rect.size.x; + h = p_item->final_clip_rect.size.y; + } + else + { + x = p_item->final_clip_rect.pos.x; + y = 240 - (p_item->final_clip_rect.pos.y + p_item->final_clip_rect.size.y); + w = p_item->final_clip_rect.size.x; + h = p_item->final_clip_rect.size.y; + } + + _set_scissor(x, y, w, h); +} + +template +void Rasterizer3DS::_canvas_item_render_commands(CanvasItem *p_item,CanvasItem *current_clip,bool &reclip) +{ + int cc=p_item->commands.size(); + CanvasItem::Command **commands = p_item->commands.ptr(); + +// print("_canvas_item_render_commands\n"); + + for(int i=0;itype) { + case CanvasItem::Command::TYPE_LINE: { + + CanvasItem::CommandLine* line = static_cast(c); + canvas_draw_line(line->from,line->to,line->color,line->width); + } break; + case CanvasItem::Command::TYPE_RECT: { + + CanvasItem::CommandRect* rect = static_cast(c); +// canvas_draw_rect(rect->rect,rect->region,rect->source,rect->flags&CanvasItem::CommandRect::FLAG_TILE,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V,rect->texture,rect->modulate); +#if 0 + int flags=0; + + if (rect->flags&CanvasItem::CommandRect::FLAG_REGION) { + flags|=Rasterizer::CANVAS_RECT_REGION; + } + if (rect->flags&CanvasItem::CommandRect::FLAG_TILE) { + flags|=Rasterizer::CANVAS_RECT_TILE; + } + if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H) { + + flags|=Rasterizer::CANVAS_RECT_FLIP_H; + } + if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V) { + + flags|=Rasterizer::CANVAS_RECT_FLIP_V; + } +#else + + int flags=rect->flags; +#endif +// if (use_normalmap) +// _canvas_normal_set_flip(Vector2((flags&CANVAS_RECT_FLIP_H)?-1:1,(flags&CANVAS_RECT_FLIP_V)?-1:1)); + canvas_draw_rect(rect->rect,flags,rect->source,rect->texture,rect->modulate); + + } break; + case CanvasItem::Command::TYPE_STYLE: { + + CanvasItem::CommandStyle* style = static_cast(c); +// if (use_normalmap) +// _canvas_normal_set_flip(Vector2(1,1)); + canvas_draw_style_box(style->rect,style->source,style->texture,style->margin,style->draw_center,style->color); + + } break; + case CanvasItem::Command::TYPE_PRIMITIVE: { + +// if (use_normalmap) +// _canvas_normal_set_flip(Vector2(1,1)); + CanvasItem::CommandPrimitive* primitive = static_cast(c); + canvas_draw_primitive(primitive->points,primitive->colors,primitive->uvs,primitive->texture,primitive->width); + } break; + case CanvasItem::Command::TYPE_POLYGON: { + +// if (use_normalmap) +// _canvas_normal_set_flip(Vector2(1,1)); + CanvasItem::CommandPolygon* polygon = static_cast(c); + canvas_draw_polygon(polygon->count,polygon->indices.ptr(),polygon->points.ptr(),polygon->uvs.ptr(),polygon->colors.ptr(),polygon->texture,polygon->colors.size()==1); + + } break; + + case CanvasItem::Command::TYPE_POLYGON_PTR: { + +// if (use_normalmap) +// _canvas_normal_set_flip(Vector2(1,1)); + CanvasItem::CommandPolygonPtr* polygon = static_cast(c); + canvas_draw_polygon(polygon->count,polygon->indices,polygon->points,polygon->uvs,polygon->colors,polygon->texture,false); + } break; + case CanvasItem::Command::TYPE_CIRCLE: { + + CanvasItem::CommandCircle* circle = static_cast(c); + static const int numpoints=32; + Vector2 points[numpoints+1]; + points[numpoints]=circle->pos; + int indices[numpoints*3]; + + for(int i=0;ipos+Vector2( Math::sin(i*Math_PI*2.0/numpoints),Math::cos(i*Math_PI*2.0/numpoints) )*circle->radius; + indices[i*3+0]=i; + indices[i*3+1]=(i+1)%numpoints; + indices[i*3+2]=numpoints; + } + canvas_draw_polygon(numpoints*3,indices,points,NULL,&circle->color,RID(),true); + //canvas_draw_circle(circle->indices.size(),circle->indices.ptr(),circle->points.ptr(),circle->uvs.ptr(),circle->colors.ptr(),circle->texture,circle->colors.size()==1); + } break; + case CanvasItem::Command::TYPE_TRANSFORM: { + CanvasItem::CommandTransform* transform = static_cast(c); + canvas_set_transform(transform->xform); + } break; + case CanvasItem::Command::TYPE_BLEND_MODE: { + + CanvasItem::CommandBlendMode* bm = static_cast(c); + canvas_set_blend_mode(bm->blend_mode); + + } break; + case CanvasItem::Command::TYPE_CLIP_IGNORE: { + + CanvasItem::CommandClipIgnore* ci = static_cast(c); + if (current_clip) { + + if (ci->ignore!=reclip) { + if (ci->ignore) { + C3D_SetScissor(GPU_SCISSOR_DISABLE, 0, 0, 0, 0); + reclip = true; + } else { + _set_canvas_scissor(current_clip); + reclip=false; + } + } + } + } break; + } + } + +} + +void Rasterizer3DS::canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light) +{ +// print("canvas_render_items Z:%d\n", p_z); + + canvas_opacity=1.0; +// canvas_use_modulate=p_modulate!=Color(1,1,1,1); +// canvas_modulate=p_modulate; + +// C3D_FixedAttribSet(2, p_modulate.r, p_modulate.g, p_modulate.b, canvas_opacity); +// C3D_FixedAttribSet(2, 1.f, 1.f, 1.f, 1.f); + + CanvasItem *current_clip = NULL; + + while(p_item_list) + { + CanvasItem *ci = p_item_list; + + // Handle clipping (scissor test) + if (current_clip != ci->final_clip_owner) + { + current_clip = ci->final_clip_owner; + if (current_clip) + { +// int x, y, w, h; +// +// if (current_rt) { +// x = current_clip->final_clip_rect.pos.x; +// y = current_clip->final_clip_rect.pos.y; +// w = current_clip->final_clip_rect.size.x; +// h = current_clip->final_clip_rect.size.y; +// } +// else { +// x = current_clip->final_clip_rect.pos.x; +// y = 240 - (current_clip->final_clip_rect.pos.y + current_clip->final_clip_rect.size.y); +// w = current_clip->final_clip_rect.size.x; +// h = current_clip->final_clip_rect.size.y; +// } +// _set_scissor(x, y, w, h); + _set_canvas_scissor(current_clip); + } + else + C3D_SetScissor(GPU_SCISSOR_DISABLE, 0, 0, 0, 0); + } + + // Handle material/shader + CanvasItem *material_owner = ci->material_owner?ci->material_owner:ci; + CanvasItemMaterial *material = material_owner->material; + + _set_uniform(canvas_shader->location_modelview,ci->final_transform); + _set_uniform(canvas_shader->location_extra, Matrix32()); + + bool unshaded = (material && material->shading_mode==VS::CANVAS_ITEM_SHADING_UNSHADED) || ci->blend_mode!=VS::MATERIAL_BLEND_MODE_MIX; + + bool reclip=false; + + if (ci==p_item_list || ci->blend_mode!=canvas_blend_mode) + canvas_set_blend_mode(ci->blend_mode); + + canvas_opacity = ci->final_opacity; + + if (unshaded || (p_modulate.a>0.001 && (!material || material->shading_mode!=VS::CANVAS_ITEM_SHADING_ONLY_LIGHT) && !ci->light_masked )) + _canvas_item_render_commands(ci, current_clip, reclip); + + if (reclip) + { + _set_canvas_scissor(current_clip); + } + + p_item_list = p_item_list->next; + } + + if (current_clip) + C3D_SetScissor(GPU_SCISSOR_DISABLE, 0, 0, 0, 0); +} +#endif +/* ENVIRONMENT */ + +RID Rasterizer3DS::environment_create() +{ + print("environment_create\n"); + Environment * env = memnew( Environment ); + return environment_owner.make_rid(env); +} + +void Rasterizer3DS::environment_set_background(RID p_env,VS::EnvironmentBG p_bg) +{ + ERR_FAIL_INDEX(p_bg,VS::ENV_BG_MAX); + Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND(!env); + env->bg_mode=p_bg; +} + +VS::EnvironmentBG Rasterizer3DS::environment_get_background(RID p_env) const{ + + const Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND_V(!env,VS::ENV_BG_MAX); + return env->bg_mode; +} + +void Rasterizer3DS::environment_set_background_param(RID p_env,VS::EnvironmentBGParam p_param, const Variant& p_value){ + + ERR_FAIL_INDEX(p_param,VS::ENV_BG_PARAM_MAX); + Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND(!env); + env->bg_param[p_param]=p_value; + +} +Variant Rasterizer3DS::environment_get_background_param(RID p_env,VS::EnvironmentBGParam p_param) const{ + + ERR_FAIL_INDEX_V(p_param,VS::ENV_BG_PARAM_MAX,Variant()); + const Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND_V(!env,Variant()); + return env->bg_param[p_param]; + +} + +void Rasterizer3DS::environment_set_group(RID p_env,VS::Group p_param, const Variant& p_value){ + + ERR_FAIL_INDEX(p_param,VS::ENV_GROUP_MAX); + Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND(!env); + env->group[p_param]=p_value; + +} +Variant Rasterizer3DS::environment_get_group(RID p_env,VS::Group p_param) const{ + + ERR_FAIL_INDEX_V(p_param,VS::ENV_GROUP_MAX,Variant()); + const Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND_V(!env,Variant()); + return env->group[p_param]; + +} + +void Rasterizer3DS::environment_set_enable_fx(RID p_env,VS::EnvironmentFx p_effect,bool p_enabled){ + + ERR_FAIL_INDEX(p_effect,VS::ENV_FX_MAX); + Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND(!env); + env->fx_enabled[p_effect]=p_enabled; +} +bool Rasterizer3DS::environment_is_fx_enabled(RID p_env,VS::EnvironmentFx p_effect) const{ + + ERR_FAIL_INDEX_V(p_effect,VS::ENV_FX_MAX,false); + const Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND_V(!env,false); + return env->fx_enabled[p_effect]; + +} + +void Rasterizer3DS::environment_fx_set_param(RID p_env,VS::EnvironmentFxParam p_param,const Variant& p_value){ + + ERR_FAIL_INDEX(p_param,VS::ENV_FX_PARAM_MAX); + Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND(!env); + env->fx_param[p_param]=p_value; +} +Variant Rasterizer3DS::environment_fx_get_param(RID p_env,VS::EnvironmentFxParam p_param) const{ + + ERR_FAIL_INDEX_V(p_param,VS::ENV_FX_PARAM_MAX,Variant()); + const Environment * env = environment_owner.get(p_env); + ERR_FAIL_COND_V(!env,Variant()); + return env->fx_param[p_param]; + +} + + +RID Rasterizer3DS::sampled_light_dp_create(int p_width,int p_height) { + + return sampled_light_owner.make_rid(memnew(SampledLight)); +} + +void Rasterizer3DS::sampled_light_dp_update(RID p_sampled_light, const Color *p_data, float p_multiplier) { + + +} + + +/*MISC*/ + +bool Rasterizer3DS::is_texture(const RID& p_rid) const { + + return texture_owner.owns(p_rid); +} +bool Rasterizer3DS::is_material(const RID& p_rid) const { + + return material_owner.owns(p_rid); +} +bool Rasterizer3DS::is_mesh(const RID& p_rid) const { + + return mesh_owner.owns(p_rid); +} + +bool Rasterizer3DS::is_immediate(const RID& p_rid) const { + + return immediate_owner.owns(p_rid); +} + +bool Rasterizer3DS::is_multimesh(const RID& p_rid) const { + + return multimesh_owner.owns(p_rid); +} +bool Rasterizer3DS::is_particles(const RID &p_beam) const { + + return particles_owner.owns(p_beam); +} + +bool Rasterizer3DS::is_light(const RID& p_rid) const { + + return light_owner.owns(p_rid); +} +bool Rasterizer3DS::is_light_instance(const RID& p_rid) const { + + return light_instance_owner.owns(p_rid); +} +bool Rasterizer3DS::is_particles_instance(const RID& p_rid) const { + + return particles_instance_owner.owns(p_rid); +} +bool Rasterizer3DS::is_skeleton(const RID& p_rid) const { + + return skeleton_owner.owns(p_rid); +} +bool Rasterizer3DS::is_environment(const RID& p_rid) const { + + return environment_owner.owns(p_rid); +} + +bool Rasterizer3DS::is_canvas_light_occluder(const RID& p_rid) const { + + return canvas_occluder_owner.owns(p_rid); +} + +bool Rasterizer3DS::is_shader(const RID& p_rid) const { + + return shader_owner.owns(p_rid); +} + +void Rasterizer3DS::free(const RID& p_rid) { + + if (texture_owner.owns(p_rid)) { + +// print("delete texture\n"); + Texture *texture = texture_owner.get(p_rid); + texture_owner.free(p_rid); + memdelete(texture); + + } else if (shader_owner.owns(p_rid)) { + + print("delete shader\n"); + Shader *shader = shader_owner.get(p_rid); + shader_owner.free(p_rid); + memdelete(shader); + + } else if (material_owner.owns(p_rid)) { + + Material *material = material_owner.get( p_rid ); + material_owner.free(p_rid); + memdelete(material); + + } else if (mesh_owner.owns(p_rid)) { + + Mesh *mesh = mesh_owner.get(p_rid); + + for (int i=0;isurfaces.size();i++) { + Surface *surface = mesh->surfaces[i]; + if (surface->array_local) + linearFree(surface->array_local); + if (surface->index_array_local) + linearFree(surface->index_array_local); + + if (mesh->morph_target_count>0) { + + for(int i=0;imorph_target_count;i++) { + + memdelete_arr(surface->morph_targets_local[i].array); + } + memdelete_arr(surface->morph_targets_local); + surface->morph_targets_local=NULL; + } + + memdelete( mesh->surfaces[i] ); + }; + + mesh->surfaces.clear(); + mesh_owner.free(p_rid); + memdelete(mesh); + + } else if (multimesh_owner.owns(p_rid)) { + + MultiMesh *multimesh = multimesh_owner.get(p_rid); + multimesh_owner.free(p_rid); + memdelete(multimesh); + + } else if (immediate_owner.owns(p_rid)) { + + Immediate *immediate = immediate_owner.get(p_rid); + immediate_owner.free(p_rid); + memdelete(immediate); + + } else if (particles_owner.owns(p_rid)) { + + Particles *particles = particles_owner.get(p_rid); + particles_owner.free(p_rid); + memdelete(particles); + } else if (particles_instance_owner.owns(p_rid)) { + + ParticlesInstance *particles_isntance = particles_instance_owner.get(p_rid); + particles_instance_owner.free(p_rid); + memdelete(particles_isntance); + + } else if (skeleton_owner.owns(p_rid)) { + + Skeleton *skeleton = skeleton_owner.get( p_rid ); + skeleton_owner.free(p_rid); + memdelete(skeleton); + + } else if (light_owner.owns(p_rid)) { + + Light *light = light_owner.get( p_rid ); + light_owner.free(p_rid); + memdelete(light); + + } else if (light_instance_owner.owns(p_rid)) { + + LightInstance *light_instance = light_instance_owner.get( p_rid ); + light_instance_owner.free(p_rid); + memdelete( light_instance ); + + } else if (canvas_occluder_owner.owns(p_rid)) { + + CanvasOccluder *co = canvas_occluder_owner.get(p_rid); + + canvas_occluder_owner.free(p_rid); + memdelete(co); + + } else if (canvas_light_shadow_owner.owns(p_rid)) { + + CanvasLightShadow *cls = canvas_light_shadow_owner.get(p_rid); + C3D_RenderTargetDelete(cls->renderTarget); + + canvas_light_shadow_owner.free(p_rid); + memdelete(cls); + + } else if (environment_owner.owns(p_rid)) { + + Environment *env = environment_owner.get( p_rid ); + environment_owner.free(p_rid); + memdelete( env ); + } else if (sampled_light_owner.owns(p_rid)) { + + SampledLight *sampled_light = sampled_light_owner.get( p_rid ); + ERR_FAIL_COND(!sampled_light); + + sampled_light_owner.free(p_rid); + memdelete( sampled_light ); + + }; +} + + +void Rasterizer3DS::custom_shade_model_set_shader(int p_model, RID p_shader) { + + +}; + +RID Rasterizer3DS::custom_shade_model_get_shader(int p_model) const { + + return RID(); +}; + +void Rasterizer3DS::custom_shade_model_set_name(int p_model, const String& p_name) { + +}; + +String Rasterizer3DS::custom_shade_model_get_name(int p_model) const { + + return String(); +}; + +void Rasterizer3DS::custom_shade_model_set_param_info(int p_model, const List& p_info) { + +}; + +void Rasterizer3DS::custom_shade_model_get_param_info(int p_model, List* p_info) const { + +}; + + + + +void Rasterizer3DS::_render_list_forward(RenderList *p_render_list,const Transform& p_view_transform, const Transform& p_view_transform_inverse,const CameraMatrix& p_projection,bool p_reverse_cull,bool p_fragment_light,bool p_alpha_pass) +{ + print("_render_list_forward\n"); + + if (current_rt && current_rt_vflip) { + //p_reverse_cull=!p_reverse_cull; +// glFrontFace(GL_CCW); + + } + + const Material *prev_material=NULL; + uint16_t prev_light=0x777E; + const Geometry *prev_geometry_cmp=NULL; + uint8_t prev_light_type=0xEF; + const Skeleton *prev_skeleton =NULL; + uint8_t prev_sort_flags=0xFF; + const BakedLightData *prev_baked_light=NULL; + RID prev_baked_light_texture; + const float *prev_morph_values=NULL; + int prev_receive_shadows_state=-1; + + +/* + material_shader.set_conditional(MaterialShaderGLES2::USE_VERTEX_LIGHTING,!shadow && !p_fragment_light); + material_shader.set_conditional(MaterialShaderGLES2::USE_FRAGMENT_LIGHTING,!shadow && p_fragment_light); + material_shader.set_conditional(MaterialShaderGLES2::USE_SKELETON,false); + + if (shadow) { + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_TYPE_DIRECTIONAL,false); + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_TYPE_OMNI,false); + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_TYPE_SPOT,false); + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_SHADOW,false); + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_PSSM,false); + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_PSSM4,false); + material_shader.set_conditional(MaterialShaderGLES2::SHADELESS,false); + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE,false); + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,false); +// material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_TEXTURE,false); + + } +*/ + + +// bool stores_glow = !shadow && (current_env && current_env->fx_enabled[VS::ENV_FX_GLOW]) && !p_alpha_pass; + float sampled_light_dp_multiplier=1.0; + + bool prev_blend=false; +// glDisable(GL_BLEND); + /* + C3D_Mtx material = + { + { + { { 0.0f, 0.2f, 0.2f, 0.2f } }, // Ambient + { { 0.0f, 0.8f, 0.8f, 0.4f } }, // Diffuse + { { 0.0f, 0.8f, 0.8f, 0.8f } }, // Specular + { { 1.0f, 0.0f, 0.0f, 0.0f } }, // Emission + } + }; + + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, scene_shader->location_material, &material);*/ + for (int i=0;ielement_count;i++) { + + RenderList::Element *e = p_render_list->elements[i]; + const Material *material = e->material; + uint16_t light = e->light; + uint8_t light_type = e->light_type; + uint8_t sort_flags= e->sort_flags; + const Skeleton *skeleton = e->skeleton; + const Geometry *geometry_cmp = e->geometry_cmp; + const BakedLightData *baked_light = e->instance->baked_light; + const float *morph_values = e->instance->morph_values.ptr(); + // int receive_shadows_state = e->instance->receive_shadows == true ? 1 : 0; + + bool rebind=false; + bool bind_baked_light_octree=false; + bool bind_baked_lightmap=false; + bool additive=false; + bool bind_dp_sampler=false; + +/* + if (!shadow) { + + if (texscreen_used && !texscreen_copied && material->shader_cache && material->shader_cache->valid && material->shader_cache->has_texscreen) { + texscreen_copied=true; + _copy_to_texscreen(); + + //force reset state + prev_material=NULL; + prev_light=0x777E; + prev_geometry_cmp=NULL; + prev_light_type=0xEF; + prev_skeleton =NULL; + prev_sort_flags=0xFF; + prev_morph_values=NULL; + prev_receive_shadows_state=-1; + glEnable(GL_BLEND); + glDepthMask(GL_TRUE); + glEnable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + + } + + if (light_type!=prev_light_type || receive_shadows_state!=prev_receive_shadows_state) { + + if (material->flags[VS::MATERIAL_FLAG_UNSHADED] || current_debug==VS::SCENARIO_DEBUG_SHADELESS) { + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_TYPE_DIRECTIONAL,false); + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_TYPE_OMNI,false); + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_TYPE_SPOT,false); + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_SHADOW,false); + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_PSSM,false); + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_PSSM4,false); + material_shader.set_conditional(MaterialShaderGLES2::SHADELESS,true); + } else { + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_TYPE_DIRECTIONAL,(light_type&0x3)==VS::LIGHT_DIRECTIONAL); + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_TYPE_OMNI,(light_type&0x3)==VS::LIGHT_OMNI); + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_TYPE_SPOT,(light_type&0x3)==VS::LIGHT_SPOT); + if (receive_shadows_state==1) { + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_SHADOW,(light_type&0x8)); + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_PSSM,(light_type&0x10)); + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_PSSM4,(light_type&0x20)); + } + else { + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_SHADOW,false); + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_PSSM,false); + material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_PSSM4,false); + } + material_shader.set_conditional(MaterialShaderGLES2::SHADELESS,false); + } + + rebind=true; + } + + + if (!*e->additive_ptr) { + + additive=false; + *e->additive_ptr=true; + } else { + additive=true; + } + + + if (stores_glow) + material_shader.set_conditional(MaterialShaderGLES2::USE_GLOW,!additive); + + + bool desired_blend=false; + VS::MaterialBlendMode desired_blend_mode=VS::MATERIAL_BLEND_MODE_MIX; + + if (additive) { + desired_blend=true; + desired_blend_mode=VS::MATERIAL_BLEND_MODE_ADD; + } else { + desired_blend=p_alpha_pass; + desired_blend_mode=material->blend_mode; + } + + if (prev_blend!=desired_blend) { + + if (desired_blend) { + glEnable(GL_BLEND); + if (!current_rt || !current_rt_transparent) + glColorMask(1,1,1,0); + } else { + glDisable(GL_BLEND); + glColorMask(1,1,1,1); + + } + + prev_blend=desired_blend; + } + + if (desired_blend && desired_blend_mode!=current_blend_mode) { + + + switch(desired_blend_mode) { + + case VS::MATERIAL_BLEND_MODE_MIX: { + glBlendEquation(GL_FUNC_ADD); + if (current_rt && current_rt_transparent) { +// glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + else { +// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + } break; + case VS::MATERIAL_BLEND_MODE_ADD: { + +// glBlendEquation(GL_FUNC_ADD); +// glBlendFunc(p_alpha_pass?GL_SRC_ALPHA:GL_ONE,GL_ONE); + + } break; + case VS::MATERIAL_BLEND_MODE_SUB: { + +// glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); +// glBlendFunc(GL_SRC_ALPHA,GL_ONE); + } break; + case VS::MATERIAL_BLEND_MODE_MUL: { + glBlendEquation(GL_FUNC_ADD); + if (current_rt && current_rt_transparent) { +// glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + else { +// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + } break; + + } + + current_blend_mode=desired_blend_mode; + } + + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE,false); + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,false); + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_DP_SAMPLER,false); + + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_COLOR, false); + + + if (material->flags[VS::MATERIAL_FLAG_UNSHADED] == false && current_debug != VS::SCENARIO_DEBUG_SHADELESS) { + + if (baked_light != NULL) { + if (baked_light->realtime_color_enabled) { + float realtime_energy = baked_light->realtime_energy; + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_COLOR, true); + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_COLOR, Vector3(baked_light->realtime_color.r*realtime_energy, baked_light->realtime_color.g*realtime_energy, baked_light->realtime_color.b*realtime_energy)); + } + } + + if (e->instance->sampled_light.is_valid()) { + + SampledLight *sl = sampled_light_owner.get(e->instance->sampled_light); + if (sl) { + + baked_light = NULL; //can't mix + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_DP_SAMPLER, true); + glActiveTexture(GL_TEXTURE0 + max_texture_units - 3); + glBindTexture(GL_TEXTURE_2D, sl->texture); //bind the texture + sampled_light_dp_multiplier = sl->multiplier; + bind_dp_sampler = true; + } + } + + + if (!additive && baked_light) { + + if (baked_light->mode == VS::BAKED_LIGHT_OCTREE && baked_light->octree_texture.is_valid() && e->instance->baked_light_octree_xform) { + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE, true); + bind_baked_light_octree = true; + if (prev_baked_light != baked_light) { + Texture *tex = texture_owner.get(baked_light->octree_texture); + if (tex) { + + glActiveTexture(GL_TEXTURE0 + max_texture_units - 3); + glBindTexture(tex->target, tex->tex_id); //bind the texture + } + if (baked_light->light_texture.is_valid()) { + Texture *texl = texture_owner.get(baked_light->light_texture); + if (texl) { + glActiveTexture(GL_TEXTURE0 + max_texture_units - 4); + glBindTexture(texl->target, texl->tex_id); //bind the light texture + } + } + + } + } + else if (baked_light->mode == VS::BAKED_LIGHT_LIGHTMAPS) { + + + int lightmap_idx = e->instance->baked_lightmap_id; + + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP, false); + bind_baked_lightmap = false; + + + if (baked_light->lightmaps.has(lightmap_idx)) { + + + RID texid = baked_light->lightmaps[lightmap_idx]; + + if (prev_baked_light != baked_light || texid != prev_baked_light_texture) { + + + Texture *tex = texture_owner.get(texid); + if (tex) { + + glActiveTexture(GL_TEXTURE0 + max_texture_units - 3); + glBindTexture(tex->target, tex->tex_id); //bind the texture + } + + prev_baked_light_texture = texid; + } + + if (texid.is_valid()) { + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP, true); + bind_baked_lightmap = true; + } + + } + } + } + + if (int(prev_baked_light != NULL) ^ int(baked_light != NULL)) { + rebind = true; + } + } + } // !shadow + + if (sort_flags!=prev_sort_flags) { + + if (sort_flags&RenderList::SORT_FLAG_INSTANCING) { + material_shader.set_conditional(MaterialShaderGLES2::USE_UNIFORM_INSTANCING,!use_texture_instancing && !use_attribute_instancing); + material_shader.set_conditional(MaterialShaderGLES2::USE_ATTRIBUTE_INSTANCING,use_attribute_instancing); + material_shader.set_conditional(MaterialShaderGLES2::USE_TEXTURE_INSTANCING,use_texture_instancing); + } else { + material_shader.set_conditional(MaterialShaderGLES2::USE_UNIFORM_INSTANCING,false); + material_shader.set_conditional(MaterialShaderGLES2::USE_ATTRIBUTE_INSTANCING,false); + material_shader.set_conditional(MaterialShaderGLES2::USE_TEXTURE_INSTANCING,false); + } + rebind=true; + } + + if (use_hw_skeleton_xform && (skeleton!=prev_skeleton||morph_values!=prev_morph_values)) { + if (!prev_skeleton || !skeleton) + rebind=true; //went from skeleton <-> no skeleton, needs rebind + + if (morph_values==NULL) + _setup_skeleton(skeleton); + else + _setup_skeleton(NULL); + } +*/ + if (material!=prev_material || rebind) { + + rebind = _setup_material(e->geometry,material,additive,!p_alpha_pass); + + print("Setup material\n"); + _rinfo.mat_change_count++; + } else { + + if (prev_skeleton!=skeleton) { + //_setup_material_skeleton(material,skeleton); + }; + } + + + if (geometry_cmp!=prev_geometry_cmp || prev_skeleton!=skeleton) { + + _setup_geometry(e->geometry, material,e->skeleton,e->instance->morph_values.ptr()); + _rinfo.surface_count++; +// DEBUG_TEST_ERROR("Setup geometry"); + }; + + // if (i==0 || light!=prev_light || rebind) { + // if (e->light!=0xFFFF) { + _setup_light(e->light); + // } +// _setup_lights(e->lights,e->light_count); + // } +/* + if (bind_baked_light_octree && (baked_light!=prev_baked_light || rebind)) { + + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_INVERSE_TRANSFORM, *e->instance->baked_light_octree_xform); + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LATTICE_SIZE, baked_light->octree_lattice_size); + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LATTICE_DIVIDE, baked_light->octree_lattice_divide); + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_STEPS, baked_light->octree_steps); + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_TEX,max_texture_units-3); + if (baked_light->light_texture.is_valid()) { + + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LIGHT_TEX,max_texture_units-4); + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LIGHT_PIX_SIZE,baked_light->light_tex_pixel_size); + } else { + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LIGHT_TEX,max_texture_units-3); + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LIGHT_PIX_SIZE,baked_light->octree_tex_pixel_size); + } + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_MULTIPLIER,baked_light->texture_multiplier); + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_PIX_SIZE,baked_light->octree_tex_pixel_size); + + + } + + if (bind_baked_lightmap && (baked_light!=prev_baked_light || rebind)) { + + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_LIGHTMAP, max_texture_units-3); + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_LIGHTMAP_MULTIPLIER, baked_light->lightmap_multiplier); + + } + + if (bind_dp_sampler) { + + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_DP_SAMPLER_MULTIPLIER,sampled_light_dp_multiplier); + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_DP_SAMPLER,max_texture_units-3); + } + + _set_cull(e->mirror,p_reverse_cull); + + + if (i==0 || rebind) { + material_shader.set_uniform(MaterialShaderGLES2::CAMERA_INVERSE_TRANSFORM, p_view_transform_inverse); + material_shader.set_uniform(MaterialShaderGLES2::PROJECTION_TRANSFORM, p_projection); + if (!shadow) { + + if (!additive && current_env && current_env->fx_enabled[VS::ENV_FX_AMBIENT_LIGHT]) { + Color ambcolor = _convert_color(current_env->fx_param[VS::ENV_FX_PARAM_AMBIENT_LIGHT_COLOR]); + float ambnrg = current_env->fx_param[VS::ENV_FX_PARAM_AMBIENT_LIGHT_ENERGY]; + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_LIGHT,Vector3(ambcolor.r*ambnrg,ambcolor.g*ambnrg,ambcolor.b*ambnrg)); + } else { + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_LIGHT,Vector3()); + } + } + + _rinfo.shader_change_count++; + } + + if (skeleton != prev_skeleton || rebind) { + if (skeleton && morph_values == NULL) { + material_shader.set_uniform(MaterialShaderGLES2::SKELETON_MATRICES, max_texture_units - 2); + material_shader.set_uniform(MaterialShaderGLES2::SKELTEX_PIXEL_SIZE, skeleton->pixel_size); + } + } +*/ +// if (e->instance->billboard || e->instance->billboard_y || e->instance->depth_scale) { + if (false) { + print("billboard\n"); + Transform xf=e->instance->transform; + if (e->instance->depth_scale) { + + if (p_projection.matrix[3][3]) { + //orthogonal matrix, try to do about the same + //with viewport size + //real_t w = Math::abs( 1.0/(2.0*(p_projection.matrix[0][0])) ); + real_t h = Math::abs( 1.0/(2.0*p_projection.matrix[1][1]) ); + float sc = (h*2.0); //consistent with Y-fov + xf.basis.scale( Vector3(sc,sc,sc)); + } else { + //just scale by depth + real_t sc = -camera_plane.distance_to(xf.origin); + xf.basis.scale( Vector3(sc,sc,sc)); + } + } + + if (e->instance->billboard) { + + Vector3 scale = xf.basis.get_scale(); + + if (current_rt && current_rt_vflip) { + xf.set_look_at(xf.origin, xf.origin + p_view_transform.get_basis().get_axis(2), -p_view_transform.get_basis().get_axis(1)); + } else { + xf.set_look_at(xf.origin, xf.origin + p_view_transform.get_basis().get_axis(2), p_view_transform.get_basis().get_axis(1)); + } + + xf.basis.scale(scale); + } + + if (e->instance->billboard_y) { + + Vector3 scale = xf.basis.get_scale(); + Vector3 look_at = p_view_transform.get_origin(); + look_at.y = 0.0; + Vector3 look_at_norm = look_at.normalized(); + + if (current_rt && current_rt_vflip) { + xf.set_look_at(xf.origin,xf.origin + look_at_norm, Vector3(0.0, -1.0, 0.0)); + } else { + xf.set_look_at(xf.origin,xf.origin + look_at_norm, Vector3(0.0, 1.0, 0.0)); + } + xf.basis.scale(scale); + } +// material_shader.set_uniform(MaterialShaderGLES2::WORLD_TRANSFORM, xf); + + } else { +// Transform tr = camera_transform_inverse * e->instance->transform; + _set_uniform(scene_shader->location_modelview, e->instance->transform); +// material_shader.set_uniform(MaterialShaderGLES2::WORLD_TRANSFORM, e->instance->transform); + } + +// material_shader.set_uniform(MaterialShaderGLES2::NORMAL_MULT, e->mirror?-1.0:1.0); +// material_shader.set_uniform(MaterialShaderGLES2::CONST_LIGHT_MULT,additive?0.0:1.0); + + + _render(e->geometry, material, skeleton,e->owner,e->instance->transform); +// DEBUG_TEST_ERROR("Rendering"); + + prev_material=material; + prev_skeleton=skeleton; + prev_geometry_cmp=geometry_cmp; + prev_light=e->light; + prev_light_type=e->light_type; + prev_sort_flags=sort_flags; + prev_baked_light=baked_light; + prev_morph_values=morph_values; + // prev_receive_shadows_state=receive_shadows_state; + } + + //print_line("shaderchanges: "+itos(p_alpha_pass)+": "+itos(_rinfo.shader_change_count)); + + + if (current_rt && current_rt_vflip) { +// glFrontFace(GL_CW); + } + +}; +/* +void Rasterizer3DS::_setup_fixed_material(const Geometry *p_geometry,const Material *p_material) { + + Color diffuse_color=p_material->parameters[VS::FIXED_MATERIAL_PARAM_DIFFUSE]; + + _set_uniform(scene_shader->location_material, diffuse_color); +}*/ + +bool Rasterizer3DS::_setup_material(const Geometry *p_geometry,const Material *p_material,bool p_no_const_light,bool p_opaque_pass) +{ + Texture *texture = NULL; + + if (p_material->flags[VS::MATERIAL_FLAG_DOUBLE_SIDED]) { +// glDisable(GL_CULL_FACE); + // C3D_CullFace(GPU_CULL_NONE); + C3D_CullFace(GPU_CULL_FRONT_CCW); + + } else { +// glEnable(GL_CULL_FACE); + C3D_CullFace(GPU_CULL_NONE); + } + +// C3D_TexEnv* env = C3D_GetTexEnv(0); +// C3D_TexEnvSrc(env, C3D_Both, GPU_FRAGMENT_PRIMARY_COLOR, GPU_FRAGMENT_SECONDARY_COLOR, 0); +// C3D_TexEnvOp(env, C3D_Both, 0, 0, 0); +// C3D_TexEnvFunc(env, C3D_Both, GPU_ADD); + + C3D_TexEnv *env = C3D_GetTexEnv(1); + + + +// if (p_material->line_width) +// glLineWidth(p_material->line_width); +/* + //all goes to false by default + material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_PASS,shadow!=NULL); + material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_PCF,shadow_filter==SHADOW_FILTER_PCF5 || shadow_filter==SHADOW_FILTER_PCF13); + material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_PCF_HQ,shadow_filter==SHADOW_FILTER_PCF13); + material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_ESM,shadow_filter==SHADOW_FILTER_ESM); + material_shader.set_conditional(MaterialShaderGLES2::USE_LIGHTMAP_ON_UV2,p_material->flags[VS::MATERIAL_FLAG_LIGHTMAP_ON_UV2]); + material_shader.set_conditional(MaterialShaderGLES2::USE_COLOR_ATTRIB_SRGB_TO_LINEAR,p_material->flags[VS::MATERIAL_FLAG_COLOR_ARRAY_SRGB] && current_env && current_env->fx_enabled[VS::ENV_FX_SRGB]); + + if (p_opaque_pass && p_material->depth_draw_mode==VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA && p_material->shader_cache && p_material->shader_cache->has_alpha) { + + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_CLIP_ALPHA,true); + } else { + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_CLIP_ALPHA,false); + + } +*/ + +// if (!shadow) { + + bool depth_test=!p_material->flags[VS::MATERIAL_FLAG_ONTOP]; + bool depth_write=p_material->depth_draw_mode!=VS::MATERIAL_DEPTH_DRAW_NEVER && (p_opaque_pass || p_material->depth_draw_mode==VS::MATERIAL_DEPTH_DRAW_ALWAYS); + //bool depth_write=!p_material->hints[VS::MATERIAL_HINT_NO_DEPTH_DRAW] && (p_opaque_pass || !p_material->hints[VS::MATERIAL_HINT_NO_DEPTH_DRAW_FOR_ALPHA]); + + if (current_depth_mask!=depth_write) + { + current_depth_mask=depth_write; +// glDepthMask( depth_write ); + } + + + if (current_depth_test!=depth_test) + { + current_depth_test=depth_test; +// if(depth_test) +// glEnable(GL_DEPTH_TEST); +// else +// glDisable(GL_DEPTH_TEST); + } + + +// material_shader.set_conditional(MaterialShaderGLES2::USE_FOG,current_env && current_env->fx_enabled[VS::ENV_FX_FOG]); +// } + + +// DEBUG_TEST_ERROR("Pre Shader Bind"); + + bool rebind=false; + +// if (p_material->shader_cache && p_material->shader_cache->valid) { + + // // reduce amount of conditional compilations + // for(int i=0;i<_tex_version_count;i++) + // material_shader.set_conditional((MaterialShaderGLES2::Conditionals)_tex_version[i],false); + + + // material_shader.set_custom_shader(p_material->shader_cache->custom_code_id); + +// if (p_material->shader_version!=p_material->shader_cache->version) { + //shader changed somehow, must update uniforms + +// _update_material_shader_params((Material*)p_material); + +// } +// material_shader.set_custom_shader(p_material->shader_cache->custom_code_id); +// rebind = material_shader.bind(); + +// DEBUG_TEST_ERROR("Shader Bind"); + + //set uniforms! + int texcoord=0; + for (Map::Element *E=p_material->shader_params.front();E;E=E->next()) + { + +// if (E->get().index<0) +// continue; + + if (!texture && E->get().istexture) { + //clearly a texture.. + RID rid = E->get().value; + print("rid:%u\n", rid.get_id()); +// int loc = material_shader.get_custom_uniform_location(E->get().index); //should be automatic.. + + texture=_bind_texture(rid); +// if (rid.is_valid()) { +// texture=texture_owner.get(rid); +// if (!texture) { +// E->get().value=RID(); //nullify, invalid texture +// rid=RID(); +// } +// } + +// glActiveTexture(GL_TEXTURE0+texcoord); +// glUniform1i(loc,texcoord); //TODO - this could happen automatically on compile... + texcoord++; + + } else if (E->get().value.get_type()==Variant::COLOR) {/* + Color c = E->get().value; + C3D_AttrInfo* attrInfo = C3D_GetAttrInfo(); + AttrInfo_Init(attrInfo); + // AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position + AttrInfo_AddFixed(attrInfo, 3); // v1=color + C3D_FixedAttribSet(3, c.r, c.g, c.b, c.a);*/ + // + // _set_uniform(scene_shader->location_material, c); + // C3D_TexEnvSrc(env, C3D_Both, GPU_PRIMARY_COLOR, (GPU_TEVSRC)0, (GPU_TEVSRC)0); + // C3D_TexEnvOpRgb(env, GPU_TEVOP_RGB_SRC_COLOR); + // C3D_TexEnvOpAlpha(env,GPU_TEVOP_A_SRC_ALPHA); + // C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE); + + // printf("a\n"); +// material_shader.set_custom_uniform(E->get().index,_convert_color(c)); + } else { +// material_shader.set_custom_uniform(E->get().index,E->get().value); + } + + } + + // _setup_fixed_material(p_geometry,p_material); + + print("texture count: %d\n", texcoord); + + if (texture) + { + print("binding material texture\n"); + C3D_TexEnvSrc(env, C3D_Both, GPU_PREVIOUS, GPU_TEXTURE0); + C3D_TexEnvOpRgb(env, GPU_TEVOP_RGB_SRC_COLOR); + C3D_TexEnvOpAlpha(env,GPU_TEVOP_A_SRC_ALPHA); + C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE); + } + else + { + print("unbinding material texture\n"); + C3D_TexEnvSrc(env, C3D_Both, GPU_PREVIOUS); + C3D_TexEnvOpRgb(env, GPU_TEVOP_RGB_SRC_COLOR); + C3D_TexEnvOpAlpha(env,GPU_TEVOP_A_SRC_ALPHA); + C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE); + } + + +// if (p_material->shader_cache->has_texscreen && framebuffer.active) { +// material_shader.set_uniform(MaterialShaderGLES2::TEXSCREEN_SCREEN_MULT,Vector2(float(viewport.width)/framebuffer.width,float(viewport.height)/framebuffer.height)); +// material_shader.set_uniform(MaterialShaderGLES2::TEXSCREEN_SCREEN_CLAMP,Color(0,0,float(viewport.width)/framebuffer.width,float(viewport.height)/framebuffer.height)); +// material_shader.set_uniform(MaterialShaderGLES2::TEXSCREEN_TEX,texcoord); +// glActiveTexture(GL_TEXTURE0+texcoord); +// glBindTexture(GL_TEXTURE_2D,framebuffer.sample_color); +// C3D_TexBind(texcoord, NULL); + +// } +// if (p_material->shader_cache->has_screen_uv) { +// material_shader.set_uniform(MaterialShaderGLES2::SCREEN_UV_MULT,Vector2(1.0/viewport.width,1.0/viewport.height)); +// } +// DEBUG_TEST_ERROR("Material parameters"); + +// if (p_material->shader_cache->uses_time) { +// material_shader.set_uniform(MaterialShaderGLES2::TIME,Math::fmod(last_time,shader_time_rollback)); +// draw_next_frame=true; +// } + //if uses TIME - draw_next_frame=true + + +// } else { + +// material_shader.set_custom_shader(0); +// rebind = material_shader.bind(); + +// DEBUG_TEST_ERROR("Shader bind2"); +// } + + +/* + if (shadow) { + + float zofs = shadow->base->vars[VS::LIGHT_PARAM_SHADOW_Z_OFFSET]; + float zslope = shadow->base->vars[VS::LIGHT_PARAM_SHADOW_Z_SLOPE_SCALE]; + if (shadow_pass>=1 && shadow->base->type==VS::LIGHT_DIRECTIONAL) { + float m = Math::pow(shadow->base->directional_shadow_param[VS::LIGHT_DIRECTIONAL_SHADOW_PARAM_PSSM_ZOFFSET_SCALE],shadow_pass); + zofs*=m; + zslope*=m; + } + material_shader.set_uniform(MaterialShaderGLES2::SHADOW_Z_OFFSET,zofs); + material_shader.set_uniform(MaterialShaderGLES2::SHADOW_Z_SLOPE_SCALE,zslope); + if (shadow->base->type==VS::LIGHT_OMNI) + material_shader.set_uniform(MaterialShaderGLES2::DUAL_PARABOLOID,shadow->dp); + DEBUG_TEST_ERROR("Shadow uniforms"); + + } + + + if (current_env && current_env->fx_enabled[VS::ENV_FX_FOG]) { + + Color col_begin = current_env->fx_param[VS::ENV_FX_PARAM_FOG_BEGIN_COLOR]; + Color col_end = current_env->fx_param[VS::ENV_FX_PARAM_FOG_END_COLOR]; + col_begin=_convert_color(col_begin); + col_end=_convert_color(col_end); + float from = current_env->fx_param[VS::ENV_FX_PARAM_FOG_BEGIN]; + float zf = camera_z_far; + float curve = current_env->fx_param[VS::ENV_FX_PARAM_FOG_ATTENUATION]; + material_shader.set_uniform(MaterialShaderGLES2::FOG_PARAMS,Vector3(from,zf,curve)); + material_shader.set_uniform(MaterialShaderGLES2::FOG_COLOR_BEGIN,Vector3(col_begin.r,col_begin.g,col_begin.b)); + material_shader.set_uniform(MaterialShaderGLES2::FOG_COLOR_END,Vector3(col_end.r,col_end.g,col_end.b)); + } +*/ + + + //material_shader.set_uniform(MaterialShaderGLES2::TIME,Math::fmod(last_time,300.0)); + //if uses TIME - draw_next_frame=true + + return rebind; +} + +void Rasterizer3DS::_setup_light(uint16_t p_light) +{ + + LightInstance *li=lights[p_light]; + Light *l=li->base; + Color col_diffuse = (l->colors[VS::LIGHT_COLOR_DIFFUSE]); + Color col_specular=(l->colors[VS::LIGHT_COLOR_SPECULAR]); + // printf("col\n"); + + + // if (l->type!=VS::LIGHT_DIRECTIONAL) { + Vector3 pos = li->transform.get_origin(); + pos = camera_transform_inverse.xform(pos); + + // C3D_FVec lightVec = FVec4_New(pos.x, pos.y, pos.z, 0.0f); + + // C3D_LightPosition(&l->light, &lightVec); + // C3D_LightDiffuse(&l->light, col_diffuse.r, col_diffuse.g, col_diffuse.b); + // C3D_LightSpecular0(&l->light, col_specular.r, col_specular.g, col_specular.b); + // printf("light\n"); + C3D_FVUnifSet(GPU_VERTEX_SHADER, scene_shader->uLoc_lightVec, pos.x, pos.y, pos.z, 0.0f); + C3D_FVUnifSet(GPU_VERTEX_SHADER, scene_shader->uLoc_lightHalfVec,pos.x, pos.y, pos.z, 0.0f); + C3D_FVUnifSet(GPU_VERTEX_SHADER, scene_shader->uLoc_lightClr, col_diffuse.r, col_diffuse.g, col_diffuse.b, 1.0f); + // } + + // if(li->near_shadow_buffer) { + // C3D_LightShadowEnable(&l->light, true); + // } +} + +Error Rasterizer3DS::_setup_geometry(const Geometry *p_geometry, const Material* p_material, const Skeleton *p_skeleton,const float *p_morphs) +{ +} + +void Rasterizer3DS::_add_geometry( const Geometry* p_geometry, const InstanceData *p_instance, const Geometry *p_geometry_cmp, const GeometryOwner *p_owner,int p_material) +{ +Material *m=NULL; + RID m_src=p_instance->material_override.is_valid() ? p_instance->material_override : p_geometry->material; + + if (m_src) + m=material_owner.get( m_src ); + + if (!m) { + m=material_owner.get( default_material ); + } + + ERR_FAIL_COND(!m); + + + if (m->last_pass!=frame) { + + m->last_pass=frame; + } + + + + + + RenderList *render_list=&opaque_render_list; + if (m->fixed_flags[VS::FIXED_MATERIAL_FLAG_USE_ALPHA] || m->blend_mode!=VS::MATERIAL_BLEND_MODE_MIX) { + render_list = &alpha_render_list; + }; + + if (!m->flags[VS::MATERIAL_FLAG_UNSHADED]) { + + int lis = p_instance->light_instances.size(); + + for(int i=0;i=RenderList::MAX_LIGHTS) + break; + + LightInstance *li=light_instance_owner.get( p_instance->light_instances[i] ); + + if (!li || li->last_pass!=scene_pass) //lit by light not in visible scene + continue; + lights[light_count++]=li; + + } + } + + RenderList::Element *e = render_list->add_element(); + + e->geometry=p_geometry; +// e->geometry_cmp=p_geometry_cmp; + e->material=m; + e->instance=p_instance; + //e->depth=camera_plane.distance_to(p_world->origin); + e->depth=camera_transform.origin.distance_to(p_instance->transform.origin); + e->owner=p_owner; + if (p_instance->skeleton.is_valid()) + e->skeleton=skeleton_owner.get(p_instance->skeleton); + else + e->skeleton=NULL; + e->mirror=p_instance->mirror; + if (m->flags[VS::MATERIAL_FLAG_INVERT_FACES]) + e->mirror=!e->mirror; + + e->light_key=0; + e->light_count=0; + + + if (!shadow) { + + + if (m->flags[VS::MATERIAL_FLAG_UNSHADED]) { + + + e->light_key--; //special key for all the shadeless people + } else if (light_count) { + + for(int i=0;ilights[i]=lights[i]->sort_key; + } + + e->light_count=light_count; + int poslight_count=light_count; + if (poslight_count>1) { + SortArray light_sort; + light_sort.sort(&e->lights[0],poslight_count); //generate an equal sort key + } + } + + } + +} + +static const GPU_Primitive_t gl_primitive[]={ + GPU_TRIANGLES, + GPU_TRIANGLES, + GPU_TRIANGLES, + GPU_TRIANGLES, + GPU_TRIANGLES, + GPU_TRIANGLE_STRIP, + GPU_TRIANGLE_FAN +}; + +void Rasterizer3DS::_render(const Geometry *p_geometry,const Material *p_material, const Skeleton* p_skeleton, const GeometryOwner *p_owner,const Transform& p_xform) +{ + _rinfo.object_count++; + + C3D_AttrInfo* attrInfo = C3D_GetAttrInfo(); + AttrInfo_Init(attrInfo); + + + C3D_BufInfo* bufInfo = C3D_GetBufInfo(); + BufInfo_Init(bufInfo); + + switch(p_geometry->type) { + + case Geometry::GEOMETRY_SURFACE: { + + Surface *s = (Surface*)p_geometry; + + bool has_tex = (s->stride > 24); +// bool has_tex = s->array[VS::ARRAY_TEX_UV].bind; + + print("stride:%d primitive:%d\n", s->stride, (int)gl_primitive[s->primitive]); + + AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=vertex + AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 3); // v1=normal + if (has_tex) + AttrInfo_AddLoader(attrInfo, 2, GPU_FLOAT, 2); // v2=tex_uv + else + { + /* + AttrInfo_AddFixed(attrInfo, 3); + C3D_FixedAttribSet(3, 1.f, 1.f, 1.f, 1.f);*/ + // AttrInfo_AddLoader(attrInfo, 3, GPU_FLOAT, 4); + // BufInfo_Add(bufInfo, s->array_local, s->stride, has_tex ? 3 : 2, has_tex ? 0x210 : 0x10); + + } + + BufInfo_Add(bufInfo, s->array_local, s->stride, has_tex ? 3 : 2, has_tex ? 0x210 : 0x10); + + _rinfo.vertex_count+=s->array_len; + + if (s->index_array_len>0) { + + if (s->index_array_local) + { + print("index len: %u\n", s->array[VS::ARRAY_INDEX].size); + + //print_line("LOCAL F: "+itos(s->format)+" C: "+itos(s->index_array_len)+" VC: "+itos(s->array_len)); +// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); +// glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len>(1<<16))?GL_UNSIGNED_INT:GL_UNSIGNED_SHORT, s->index_array_local); + + C3D_DrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array[VS::ARRAY_INDEX].size == 2) ? C3D_UNSIGNED_SHORT : C3D_UNSIGNED_BYTE, s->index_array_local); + + } + + } else { + +// glDrawArrays(gl_primitive[s->primitive],0,s->array_len); + C3D_DrawArrays(gl_primitive[s->primitive], 0, s->array_len); + + }; + + _rinfo.draw_calls++; + } break; + + case Geometry::GEOMETRY_MULTISURFACE: { + +// material_shader.bind_uniforms(); + Surface *s = static_cast(p_geometry)->surface; + const MultiMesh *mm = static_cast(p_owner); + int element_count=mm->elements.size(); + + if (element_count==0) + return; + + if (mm->visible>=0) { + element_count=MIN(element_count,mm->visible); + } + + const MultiMesh::Element *elements=&mm->elements[0]; + + _rinfo.vertex_count+=s->array_len*element_count; + + _rinfo.draw_calls+=element_count; + +/* + if (use_texture_instancing) { + //this is probably the fastest all around way if vertex texture fetch is supported + + float twd=(1.0/mm->tw)*4.0; + float thd=1.0/mm->th; + float parm[3]={0.0,01.0,(1.0f/mm->tw)}; + glActiveTexture(GL_TEXTURE0+max_texture_units-2); + glDisableVertexAttribArray(6); + glBindTexture(GL_TEXTURE_2D,mm->tex_id); + material_shader.set_uniform(MaterialShaderGLES2::INSTANCE_MATRICES,GL_TEXTURE0+max_texture_units-2); + + if (s->index_array_len>0) { + + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,s->index_id); + for(int i=0;itw>>2))*twd; + parm[1]=(i/(mm->tw>>2))*thd; + glVertexAttrib3fv(6,parm); + glDrawElements(gl_primitive[s->primitive],s->index_array_len, (s->array_len>(1<<16))?GL_UNSIGNED_INT:GL_UNSIGNED_SHORT,0); + + } + + + } else { + + for(int i=0;itw>>2))*twd; + //parm[1]=(i/(mm->tw>>2))*thd; + glVertexAttrib3fv(6,parm); + glDrawArrays(gl_primitive[s->primitive],0,s->array_len); + } + }; + + } else if (use_attribute_instancing) { + //if not, using atributes instead of uniforms can be really fast in forward rendering architectures + if (s->index_array_len>0) { + + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,s->index_id); + for(int i=0;iprimitive],s->index_array_len, (s->array_len>(1<<16))?GL_UNSIGNED_INT:GL_UNSIGNED_SHORT,0); + } + + + } else { + + for(int i=0;iprimitive],0,s->array_len); + } + }; + + + } else { + + //nothing to do, slow path (hope no hardware has to use it... but you never know) + + if (s->index_array_len>0) { + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,s->index_id); + for(int i=0;iprimitive],s->index_array_len, (s->array_len>(1<<16))?GL_UNSIGNED_INT:GL_UNSIGNED_SHORT,0); + } + + + } else { + + for(int i=0;iprimitive],0,s->array_len); + } + }; + } +*/ + } break; +/* + case Geometry::GEOMETRY_IMMEDIATE: { + + bool restore_tex=false; + const Immediate *im = static_cast( p_geometry ); + if (im->building) { + return; + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + for(const List::Element *E=im->chunks.front();E;E=E->next()) { + + const Immediate::Chunk &c=E->get(); + if (c.vertices.empty()) { + continue; + } + for(int i=0;itarget,t->tex_id); + restore_tex=true; + + + } else if (restore_tex) { + + glActiveTexture(GL_TEXTURE0+tc0_idx); + glBindTexture(GL_TEXTURE_2D,tc0_id_cache); + restore_tex=false; + } + + if (!c.normals.empty()) { + + glEnableVertexAttribArray(VS::ARRAY_NORMAL); + glVertexAttribPointer(VS::ARRAY_NORMAL, 3, GL_FLOAT, false,sizeof(Vector3),c.normals.ptr()); + + } else { + + glDisableVertexAttribArray(VS::ARRAY_NORMAL); + } + + if (!c.tangents.empty()) { + + glEnableVertexAttribArray(VS::ARRAY_TANGENT); + glVertexAttribPointer(VS::ARRAY_TANGENT, 4, GL_FLOAT, false,sizeof(Plane),c.tangents.ptr()); + + } else { + + glDisableVertexAttribArray(VS::ARRAY_TANGENT); + } + + if (!c.colors.empty()) { + + glEnableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false,sizeof(Color),c.colors.ptr()); + + } else { + + glDisableVertexAttribArray(VS::ARRAY_COLOR); + _set_color_attrib(Color(1, 1, 1,1)); + } + + + if (!c.uvs.empty()) { + + glEnableVertexAttribArray(VS::ARRAY_TEX_UV); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false,sizeof(Vector2),c.uvs.ptr()); + + } else { + + glDisableVertexAttribArray(VS::ARRAY_TEX_UV); + } + + if (!c.uvs2.empty()) { + + glEnableVertexAttribArray(VS::ARRAY_TEX_UV2); + glVertexAttribPointer(VS::ARRAY_TEX_UV2, 2, GL_FLOAT, false,sizeof(Vector2),c.uvs2.ptr()); + + } else { + + glDisableVertexAttribArray(VS::ARRAY_TEX_UV2); + } + + + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, false,sizeof(Vector3),c.vertices.ptr()); + glDrawArrays(gl_primitive[c.primitive],0,c.vertices.size()); + + + } + + + if (restore_tex) { + + glActiveTexture(GL_TEXTURE0+tc0_idx); + glBindTexture(GL_TEXTURE_2D,tc0_id_cache); + restore_tex=false; + } + + + } break; +`*/ + case Geometry::GEOMETRY_PARTICLES: { + + //print_line("particulinas"); + const Particles *particles = static_cast( p_geometry ); + ERR_FAIL_COND(!p_owner); + ParticlesInstance *particles_instance = (ParticlesInstance*)p_owner; + + ParticleSystemProcessSW &pp = particles_instance->particles_process; + float td = time_delta; //MIN(time_delta,1.0/10.0); + pp.process(&particles->data,particles_instance->transform,td); + ERR_EXPLAIN("A parameter in the particle system is not correct."); + ERR_FAIL_COND(!pp.valid); + + + Transform camera; +// if (shadow) +// camera=shadow->transform; +// else + camera=camera_transform; + + particle_draw_info.prepare(&particles->data,&pp,particles_instance->transform,camera); + _rinfo.draw_calls+=particles->data.amount; + + + _rinfo.vertex_count+=4*particles->data.amount; + + { + static const Vector3 points[4]={ + Vector3(-1.0,1.0,0), + Vector3(1.0,1.0,0), + Vector3(1.0,-1.0,0), + Vector3(-1.0,-1.0,0) + }; + static const Vector3 uvs[4]={ + Vector3(0.0,0.0,0.0), + Vector3(1.0,0.0,0.0), + Vector3(1.0,1.0,0.0), + Vector3(0,1.0,0.0) + }; + static const Vector3 normals[4]={ + Vector3(0,0,1), + Vector3(0,0,1), + Vector3(0,0,1), + Vector3(0,0,1) + }; + + static const Plane tangents[4]={ + Plane(Vector3(1,0,0),0), + Plane(Vector3(1,0,0),0), + Plane(Vector3(1,0,0),0), + Plane(Vector3(1,0,0),0) + }; + + for(int i=0;idata.amount;i++) { + + ParticleSystemDrawInfoSW::ParticleDrawInfo &pinfo=*particle_draw_info.draw_info_order[i]; + if (!pinfo.data->active) + continue; + +// material_shader.set_uniform(MaterialShaderGLES2::WORLD_TRANSFORM, pinfo.transform); +// _set_color_attrib(pinfo.color); +// _draw_primitive(4,points,normals,NULL,uvs,tangents); + } + } + + } break; + default: break; + }; +} + +void Rasterizer3DS::_draw_quad(const Rect2& p_rect) +{ + VertexArray *varray = memnew(VertexArray(4)); + varray->vertices[0].position = Vector3( p_rect.pos.x,p_rect.pos.y, 0.5f ); + varray->vertices[1].position = Vector3( p_rect.pos.x+p_rect.size.width,p_rect.pos.y, 0.5f ); + varray->vertices[2].position = Vector3( p_rect.pos.x+p_rect.size.width,p_rect.pos.y+p_rect.size.height, 0.5f ); + varray->vertices[3].position = Vector3( p_rect.pos.x,p_rect.pos.y+p_rect.size.height, 0.5f ); + + C3D_BufInfo* bufInfo = C3D_GetBufInfo(); + BufInfo_Init(bufInfo); + BufInfo_Add(bufInfo, varray->vertices, sizeof(Vertex), 2, 0x10); + + C3D_DrawArrays(GPU_TRIANGLE_FAN, 0, 4); + + vertexArrays.push_back(varray); +// C3D_Flush(); +// _draw_gui_primitive(4,coords,0,0); +// _rinfo.ci_draw_commands++; +} + +void Rasterizer3DS::_draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip, bool p_v_flip, bool p_transpose ) +{ +// print("_draw_textured_quad\n"); + VertexArray *varray = memnew(VertexArray(4)); + + Vertex v[4] = { + { + Vector3( p_rect.pos.x, p_rect.pos.y, 0.5f), + Vector2( p_src_region.pos.x/p_tex_size.width, p_src_region.pos.y/p_tex_size.height) + },{ + Vector3( p_rect.pos.x+p_rect.size.width, p_rect.pos.y, 0.5f), + Vector2((p_src_region.pos.x+p_src_region.size.width)/p_tex_size.width, p_src_region.pos.y/p_tex_size.height) + },{ + Vector3( p_rect.pos.x+p_rect.size.width, p_rect.pos.y+p_rect.size.height, 0.5f), + Vector2( (p_src_region.pos.x+p_src_region.size.width)/p_tex_size.width, (p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height) + },{ + Vector3( p_rect.pos.x,p_rect.pos.y+p_rect.size.height, 0.5f), + Vector2( p_src_region.pos.x/p_tex_size.width, (p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height) + }, + }; + + memcpy(varray->vertices, v, sizeof(v)); + + if (p_transpose) { + SWAP( varray->vertices[1].texcoord, varray->vertices[3].texcoord ); + } + if (p_h_flip) { + SWAP( varray->vertices[0].texcoord, varray->vertices[1].texcoord ); + SWAP( varray->vertices[2].texcoord, varray->vertices[3].texcoord ); + } + if (p_v_flip) { + SWAP( varray->vertices[1].texcoord, varray->vertices[2].texcoord ); + SWAP( varray->vertices[0].texcoord, varray->vertices[3].texcoord ); + } + + C3D_BufInfo* bufInfo = C3D_GetBufInfo(); + BufInfo_Init(bufInfo); + BufInfo_Add(bufInfo, varray->vertices, sizeof(Vertex), 2, 0x10); + + C3D_DrawArrays(GPU_TRIANGLE_FAN, 0, 4); + + vertexArrays.push_back(varray); +// _draw_gui_primitive(4,coords,0,texcoords); +// _rinfo.ci_draw_commands++; +} + +static const C3D_Material material = + { + { 0.2f, 0.2f, 0.2f }, //ambient + { 0.4f, 0.4f, 0.4f }, //diffuse + { 0.8f, 0.8f, 0.8f }, //specular0 + { 0.0f, 0.0f, 0.0f }, //specular1 + { 0.0f, 0.0f, 0.0f }, //emission + }; + +int Rasterizer3DS::RenderList::max_elements; + +void Rasterizer3DS::init() +{ + print("citro init "); + C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); + draw_next_frame = false; + + canvas_shader = memnew(Shader); + canvas_shader->set_data(shader_builtin_2d, sizeof(shader_builtin_2d)); + + scene_shader = memnew(Shader); + scene_shader->set_data_3d(shader_builtin_3d, sizeof(shader_builtin_3d)); + + // Setup default render target (screen framebuffer) + base_framebuffer = memnew(RenderTarget); + Texture *texture = memnew(Texture); + + base_framebuffer->target = C3D_RenderTargetCreate(480, 800, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); + C3D_RenderTargetSetOutput(base_framebuffer->target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); + C3D_RenderTargetClear(base_framebuffer->target,C3D_CLEAR_ALL,CLEAR_COLOR,0); + base_framebuffer->texture_ptr = texture; + base_framebuffer->texture = texture_owner.make_rid( texture ); + + // Frag lighting + + C3D_LightEnvInit(&lightEnv); + C3D_LightEnvBind(&lightEnv); + C3D_LightEnvMaterial(&lightEnv, &material); + + LightLut_Phong(&lut_Phong, 30); + C3D_LightEnvLut(&lightEnv, GPU_LUT_D0, GPU_LUTINPUT_LN, false, &lut_Phong); + + C3D_FVec lightVec = { { 1.0, -1.5, 0.0, 0.0 } }; + + + +// C3D_LightInit(&light, &lightEnv); +// C3D_LightColor(&light, 1.0, 1.0, 1.0); +// C3D_LightPosition(&light, &lightVec); + +// C3D_LightSpotEnable(&light, true); +// C3D_LightSpotDir(&light, 1.0, 1.0, 1.0); + /* + const C3D_Material material = + { + { 0.0f, 0.0f, 0.0f }, //ambient + { 1.0f, 0.0f, 0.4f }, //diffuse + { 0.8f, 0.8f, 0.8f }, //specular0 + { 0.0f, 0.0f, 0.0f }, //specular1 + { 0.0f, 0.0f, 0.0f }, //emission + }; + + C3D_LightEnvInit(&lightEnv); + C3D_LightEnvBind(&lightEnv); + C3D_LightEnvMaterial(&lightEnv, &material); + + LightLut_Phong(&lut_Phong, 30); + C3D_LightEnvLut(&lightEnv, GPU_LUT_D0, GPU_LUTINPUT_LN, false, &lut_Phong); + + C3D_LightInit(&light, &lightEnv);*/ + + C3D_DepthTest(false, GPU_GEQUAL, GPU_WRITE_ALL); +// C3D_CullFace(GPU_CULL_FRONT_CCW); + C3D_CullFace(GPU_CULL_NONE); + + RenderList::max_elements=GLOBAL_DEF("rasterizer/max_render_elements",(int)RenderList::DEFAULT_MAX_ELEMENTS); + if (RenderList::max_elements>64000) + RenderList::max_elements=64000; + if (RenderList::max_elements<1024) + RenderList::max_elements=1024; + + opaque_render_list.init(); + alpha_render_list.init(); + C3D_SetFrameBuf(&base_framebuffer->target->frameBuf); + + + // render_target_create(); +} + +void Rasterizer3DS::finish() +{ + print("citro finish\n"); + + memdelete(canvas_shader); + memdelete(scene_shader); + memdelete(base_framebuffer->texture_ptr); + memdelete(base_framebuffer); + + C3D_Fini(); +} + +int Rasterizer3DS::get_render_info(VS::RenderInfo p_info) { + + switch(p_info) { + + case VS::INFO_OBJECTS_IN_FRAME: { + + return _rinfo.object_count; + } break; + case VS::INFO_VERTICES_IN_FRAME: { + + return _rinfo.vertex_count; + } break; + case VS::INFO_MATERIAL_CHANGES_IN_FRAME: { + + return _rinfo.mat_change_count; + } break; + case VS::INFO_SHADER_CHANGES_IN_FRAME: { + + return _rinfo.shader_change_count; + } break; + case VS::INFO_DRAW_CALLS_IN_FRAME: { + + return _rinfo.draw_calls; + } break; + case VS::INFO_SURFACE_CHANGES_IN_FRAME: { + + return _rinfo.surface_count; + } break; + case VS::INFO_USAGE_VIDEO_MEM_TOTAL: { + + return 0; + } break; + case VS::INFO_VIDEO_MEM_USED: { + + return get_render_info(VS::INFO_TEXTURE_MEM_USED)+get_render_info(VS::INFO_VERTEX_MEM_USED); + } break; + case VS::INFO_TEXTURE_MEM_USED: { + + return _rinfo.texture_mem; + } break; + case VS::INFO_VERTEX_MEM_USED: { + + return 0; + } break; + } + + return 0; +} + +bool Rasterizer3DS::needs_to_draw_next_frame() const +{ + return false; + return draw_next_frame; +} + + +bool Rasterizer3DS::has_feature(VS::Features p_feature) const +{ + switch (p_feature) { + default: + case VS::FEATURE_MULTITHREADED: return false; + case VS::FEATURE_SHADERS: return true; + case VS::FEATURE_NEEDS_RELOAD_HOOK: return false; + } +} + +void Rasterizer3DS::restore_framebuffer() +{ + print("restore_framebuffer\n"); + current_rt = NULL; + C3D_SetFrameBuf(&base_framebuffer->target->frameBuf); +} + +Rasterizer3DS::Rasterizer3DS() +: current_rt (NULL) +{ + +}; + +Rasterizer3DS::~Rasterizer3DS() +{ + +}; + +// #endif diff --git a/platform/vita/rasterizer_vita.h b/platform/3ds/rasterizer_3ds.h similarity index 73% rename from platform/vita/rasterizer_vita.h rename to platform/3ds/rasterizer_3ds.h index 9fdcae74..49dfb6e5 100644 --- a/platform/vita/rasterizer_vita.h +++ b/platform/3ds/rasterizer_3ds.h @@ -1,11 +1,11 @@ /*************************************************************************/ -/* rasterizer_gles1.h */ +/* rasterizer_citro3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2016 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 */ @@ -26,13 +26,11 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RASTERIZER_GLES1_H -#define RASTERIZER_GLES1_H +#ifndef RASTERIZER_3DS_H +#define RASTERIZER_3DS_H #include "servers/visual/rasterizer.h" -#ifdef __psp2__ - #include "image.h" #include "rid.h" #include "servers/visual_server.h" @@ -40,96 +38,40 @@ #include "map.h" #include "camera_matrix.h" #include "sort.h" -// #include "tools/editor/scene_tree_editor.h" -#include "platform_config.h" -#ifndef GLES1_INCLUDE_H -#include -// #include "immvertex.h" -#else -#include GLES1_INCLUDE_H -#endif - #include "servers/visual/particle_system_sw.h" -/** - @author Juan Linietsky -*/ -class RasterizerGLES1 : public Rasterizer { - - enum { - - MAX_SCENE_LIGHTS=2048, - LIGHT_SPOT_BIT=0x80, - DEFAULT_SKINNED_BUFFER_SIZE = 1024 * 1024, // 10k vertices - MAX_HW_LIGHTS = 8, //yay! pvrpsp2 supports 8 hw lights - }; - #ifdef PSP - void glActiveTexture(int a1) { }; - void glClientActiveTexture(int a1) { }; - #endif - - GLuint BlurTexture; - - uint8_t *skinned_buffer; - int skinned_buffer_size; - bool pvr_supported; - bool s3tc_supported; - bool etc_supported; - bool npo2_textures_available; - bool pack_arrays; - bool use_reload_hooks; - bool is_editor; - - - Image _get_gl_image_and_format(const Image& p_image, Image::Format p_format, uint32_t p_flags,GLenum& r_gl_format,int &r_gl_components,bool &r_has_alpha_cache,bool &r_compressed); +#ifdef __3DS__ +extern "C" { +#include <3ds/types.h> +#include <3ds/gpu/gpu.h> +#include <3ds/gfx.h> +#include <3ds/gpu/gx.h> +#include <3ds/gpu/shaderProgram.h> +#include <3ds/allocator/linear.h> +} +#undef __3DS__ +#include +#define __3DS__ +#endif +class Rasterizer3DS : public Rasterizer { struct Texture { uint32_t flags; int width,height; - int alloc_width, alloc_height; + C3D_Tex tex; Image::Format format; - - GLenum target; - GLenum gl_format_cache; - int gl_components_cache; - int data_size; //original data size, useful for retrieving back - bool format_has_alpha; - bool compressed; - bool disallow_mipmaps; - int total_data_size; - Image image[6]; - - bool active; - GLuint tex_id; - - ObjectID reloader; - StringName reloader_func; - Texture() { - + tex.data = NULL; flags=width=height=0; - tex_id=0; - data_size=0; format=Image::FORMAT_GRAYSCALE; - gl_components_cache=0; - format_has_alpha=false; - active=false; - disallow_mipmaps=false; -// gen_mipmap=true; - compressed=false; - total_data_size=0; } ~Texture() { - if (tex_id!=0) { - - glDeleteTextures(1,&tex_id); - } } }; @@ -148,58 +90,99 @@ class RasterizerGLES1 : public Rasterizer { bool valid; bool has_alpha; bool use_world_transform; - + + DVLB_s* dvlb; + shaderProgram_s program; + + int location_projection; + int location_modelview; + int location_worldTransform; + int location_extra; + int location_material; + int uLoc_lightVec, uLoc_lightHalfVec, uLoc_lightClr; + + void set_data(void* data, u32 size) + { + dvlb = DVLB_ParseFile(reinterpret_cast(data), size); + shaderProgramSetVsh(&program, &dvlb->DVLE[0]); + location_projection = shaderInstanceGetUniformLocation(program.vertexShader, "projection"); + location_modelview = shaderInstanceGetUniformLocation(program.vertexShader, "modelView"); + location_worldTransform = shaderInstanceGetUniformLocation(program.vertexShader, "worldTransform"); + location_extra = shaderInstanceGetUniformLocation(program.vertexShader, "extra"); + } + + void set_data_3d(void* data, u32 size) + { + dvlb = DVLB_ParseFile(reinterpret_cast(data), size); + shaderProgramSetVsh(&program, &dvlb->DVLE[0]); + location_projection = shaderInstanceGetUniformLocation(program.vertexShader, "projection"); + location_modelview = shaderInstanceGetUniformLocation(program.vertexShader, "modelView"); + location_worldTransform = shaderInstanceGetUniformLocation(program.vertexShader, "worldTransform"); + location_extra = shaderInstanceGetUniformLocation(program.vertexShader, "extra"); + + uLoc_lightVec = shaderInstanceGetUniformLocation(program.vertexShader, "lightVec"); + uLoc_lightHalfVec = shaderInstanceGetUniformLocation(program.vertexShader, "lightHalfVec"); + uLoc_lightClr = shaderInstanceGetUniformLocation(program.vertexShader, "lightClr"); + location_material = shaderInstanceGetUniformLocation(program.vertexShader, "material"); + } + + Shader() + { + dvlb = NULL; + shaderProgramInit(&program); + } + ~Shader() + { + shaderProgramFree(&program); + if (dvlb) + DVLB_Free(dvlb); + } }; mutable RID_Owner shader_owner; + + Shader* canvas_shader; + Shader* scene_shader; + struct Material { - bool fixed_flags[VS::FIXED_MATERIAL_FLAG_MAX]; bool flags[VS::MATERIAL_FLAG_MAX]; - Variant parameters[VisualServer::FIXED_MATERIAL_PARAM_MAX]; - RID textures[VisualServer::FIXED_MATERIAL_PARAM_MAX]; + bool fixed_flags[VS::FIXED_MATERIAL_FLAG_MAX]; VS::MaterialDepthDrawMode depth_draw_mode; - Transform uv_transform; - VS::FixedMaterialTexCoordMode texcoord_mode[VisualServer::FIXED_MATERIAL_PARAM_MAX]; - VS::MaterialBlendMode blend_mode; float line_width; float point_size; - bool has_alpha; RID shader; // shader material uint64_t last_pass; + Shader *shader_cache; - Map shader_params; - + struct UniformData { + bool inuse; + bool istexture; + Variant value; + int index; + }; + + Map shader_params; Material() { - for(int i=0;i skeleton_bone_aabb; + Vector skeleton_bone_used; - bool packed; + //bool packed; struct MorphTarget { uint32_t configured_format; @@ -278,6 +260,8 @@ class RasterizerGLES1 : public Rasterizer { float uv_scale; float uv2_scale; + bool alpha_sort; + VS::PrimitiveType primitive; uint32_t format; @@ -292,9 +276,8 @@ class RasterizerGLES1 : public Rasterizer { Point2 uv_min; Point2 uv_max; - Surface() { - - + Surface() + { array_len=0; local_stride=0; morph_format=0; @@ -305,16 +288,17 @@ class RasterizerGLES1 : public Rasterizer { uv_scale=1.0; uv2_scale=1.0; + alpha_sort=false; + format=0; stride=0; morph_targets_local=0; morph_target_count=0; - array_local = index_array_local = 0; - vertex_id = index_id = 0; + array_local = index_array_local = NULL; active=false; - packed=false; + //packed=false; } ~Surface() { @@ -341,8 +325,6 @@ class RasterizerGLES1 : public Rasterizer { }; mutable RID_Owner mesh_owner; - Error _surface_set_arrays(Surface *p_surface, uint8_t *p_mem,uint8_t *p_index_mem,const Array& p_arrays,bool p_main); - struct MultiMesh; struct MultiMeshSurface : public Geometry { @@ -355,31 +337,8 @@ class RasterizerGLES1 : public Rasterizer { struct Element { - float matrix[16]; - uint8_t color[4]; - Element() { - matrix[0]=1; - matrix[1]=0; - matrix[2]=0; - matrix[3]=0; - - matrix[4]=0; - matrix[5]=1; - matrix[6]=0; - matrix[7]=0; - - matrix[8]=0; - matrix[9]=0; - matrix[10]=1; - matrix[11]=0; - - matrix[12]=0; - matrix[13]=0; - matrix[14]=0; - matrix[15]=1; - }; - - + Transform xform; + Color color; }; AABB aabb; @@ -388,29 +347,20 @@ class RasterizerGLES1 : public Rasterizer { //IDirect3DVertexBuffer9* instance_buffer; Vector elements; - Vector cache_surfaces; - mutable uint64_t last_pass; - GLuint tex_id; - int tw; - int th; - SelfList dirty_list; + MultiMesh() { + visible=-1; + } - MultiMesh() : dirty_list(this) { - tw=1; - th=1; - tex_id=0; - last_pass=0; - visible = -1; - } }; + mutable RID_Owner multimesh_owner; - mutable SelfList::List _multimesh_dirty_list; struct Immediate { + RID material; int empty; }; @@ -460,7 +410,8 @@ class RasterizerGLES1 : public Rasterizer { RID projector; bool volumetric_enabled; Color volumetric_color; - + + C3D_Light light; Light() { @@ -477,17 +428,20 @@ class RasterizerGLES1 : public Rasterizer { volumetric_enabled=false; } }; + + // C3D_Light light; + C3D_LightEnv lightEnv; + C3D_LightLut lut_Phong; struct Environment { - + Variant group[VS::ENV_GROUP_MAX]; VS::EnvironmentBG bg_mode; Variant bg_param[VS::ENV_BG_PARAM_MAX]; bool fx_enabled[VS::ENV_FX_MAX]; Variant fx_param[VS::ENV_FX_PARAM_MAX]; - Variant group[VS::ENV_GROUP_MAX]; - + Environment() { bg_mode=VS::ENV_BG_DEFAULT_COLOR; @@ -521,19 +475,16 @@ class RasterizerGLES1 : public Rasterizer { fx_param[VS::ENV_FX_PARAM_BCS_CONTRAST]=1.0; fx_param[VS::ENV_FX_PARAM_BCS_SATURATION]=1.0; + } }; mutable RID_Owner environment_owner; - Environment *current_env; - + struct SampledLight { int w,h; - GLuint texture; - float multiplier; - bool is_float; }; mutable RID_Owner sampled_light_owner; @@ -561,70 +512,121 @@ class RasterizerGLES1 : public Rasterizer { Vector3 light_vector; Vector3 spot_vector; float linear_att; - - uint64_t shadow_pass; uint64_t last_pass; uint16_t sort_key; - Vector shadow_buffers; + LightInstance() { linear_att=1.0; } + + }; - void clear_shadow_buffers() { + mutable RID_Owner light_owner; + mutable RID_Owner
4 0 0 2 0 1 0 0 2 2 1 3 7 1 4 3 1 5 6 2 6 5 2 7 7 2 8 1 3 9 7 3 10 5 3 11 0 4 12 3 4 13 1 4 14 4 5 15 1 5 16 5 5 17 4 0 18 6 0 19 2 0 20 2 1 21 6 1 22 7 1 23 6 2 24 4 2 25 5 2 26 1 3 27 3 3 28 7 3 29 0 4 30 2 4 31 3 4 32 4 5 33 0 5 34 1 5 35