void Window_Base::DrawGauge(Game_Battler* actor, int cx, int cy) { FileRequestAsync* request = AsyncHandler::RequestFile("System2", Data::system.system2_name); if (!request->IsReady()) { // Gauge refreshed each frame, so we can wait via polling request->Start(); return; } BitmapRef system2 = Cache::System2(Data::system.system2_name); bool full = actor->IsGaugeFull(); int gauge_w = actor->GetGauge() / 4; // Which gauge (0 - 2) int gauge_y = 32 + 2 * 16; // Three components of the gauge Rect gauge_left(0, gauge_y, 16, 16); Rect gauge_center(16, gauge_y, 16, 16); Rect gauge_right(32, gauge_y, 16, 16); // Full or not full bar Rect gauge_bar(full ? 64 : 48, gauge_y, 16, 16); Rect dst_rect(cx + 16, cy, 25, 16); Rect bar_rect(cx + 16, cy, gauge_w, 16); contents->Blit(cx + 0, cy, *system2, gauge_left, 255); contents->Blit(cx + 16 + 25, cy, *system2, gauge_right, 255); contents->StretchBlit(dst_rect, *system2, gauge_center, 255); contents->StretchBlit(bar_rect, *system2, gauge_bar, 255); }
/* ================================================================ コピー。 ソース画像が透明色を持っていない場合はmemory-to-memoryコピー そうでない場合は1pixelづつコピー ================================================================ */ void VnImage::Copy(const VnImage& img, const VnRect& srcRect, int dx, int dy) { // 範囲内のチェック VnRect src_rect(0, 0, img.Width(), img.Height()); src_rect &= srcRect; VnRect dst_rect(0, 0, Width(), Height()); dst_rect &= VnRect(dx, dy, src_rect.width, src_rect.height); if (GetAlpha(img.mTransColor) == 0xff) { // 不透明画像をコピー for(int y = 0; y < dst_rect.height; ++y) { memcpy(GetPixelBuf(dst_rect.x, dst_rect.y + y), img.GetPixelBuf(src_rect.x, src_rect.y + y), dst_rect.width * 4); } } else { const u_int32_t trans_color = ToMachineColor(img.mTransColor & 0xffffff00); // 透明色を考慮したコピー for(int y = 0; y < dst_rect.height; ++y) { const u_int32_t* src = img.GetPixelBuf(src_rect.x, src_rect.y + y); u_int32_t* dst = GetPixelBuf(dst_rect.x, dst_rect.y + y); for(int x = 0; x < dst_rect.width; ++x, ++dst, ++src) { // ソースが透明色でない場合に書き込む // リトルエンディアン限定(:TODO:) if (trans_color != (*src & 0x00ffffff)) { *dst = *src; } } } } // end of if (GetAlpha ...) // cerr << "VnImage::Copy " << t.GetPassed() << "(s)" << endl; }
void Plane::Draw(int /* z_order */) { if (!visible || !bitmap) return; Rect dst_rect(0, 0, DisplayUi->GetWidth(), DisplayUi->GetHeight()); bitmap_screen->BlitScreenTiled(bitmap->GetRect(), dst_rect, ox, oy); }
void ViewportSprite::_notification(int p_what) { switch(p_what) { case NOTIFICATION_ENTER_TREE: { if (!viewport_path.is_empty()) { Node *n = get_node(viewport_path); ERR_FAIL_COND(!n); Viewport *vp=n->cast_to<Viewport>(); ERR_FAIL_COND(!vp); Ref<RenderTargetTexture> rtt = vp->get_render_target_texture(); texture=rtt; texture->connect("changed",this,"update"); item_rect_changed(); } } break; case NOTIFICATION_EXIT_TREE: { if (texture.is_valid()) { texture->disconnect("changed",this,"update"); texture=Ref<Texture>(); } } break; case NOTIFICATION_DRAW: { if (texture.is_null()) return; RID ci = get_canvas_item(); /* texture->draw(ci,Point2()); break; */ Size2i s; Rect2i src_rect; s = texture->get_size(); src_rect.size=s; Point2 ofs=offset; if (centered) ofs-=s/2; if (OS::get_singleton()->get_use_pixel_snap()) { ofs=ofs.floor(); } Rect2 dst_rect(ofs,s); texture->draw_rect_region(ci,dst_rect,src_rect,modulate); } break; } }
void Sprite::_notification(int p_what) { switch(p_what) { case NOTIFICATION_DRAW: { if (texture.is_null()) return; RID ci = get_canvas_item(); /* texture->draw(ci,Point2()); break; */ Size2 s; Rect2 src_rect; if (region) { s=region_rect.size; src_rect=region_rect; } else { s = Size2(texture->get_size()); s=s/Size2(hframes,vframes); src_rect.size=s; src_rect.pos.x+=float(frame%hframes)*s.x; src_rect.pos.y+=float(frame/hframes)*s.y; } Point2 ofs=offset; if (centered) ofs-=s/2; if (OS::get_singleton()->get_use_pixel_snap()) { ofs=ofs.floor(); } Rect2 dst_rect(ofs,s); if (hflip) dst_rect.size.x=-dst_rect.size.x; if (vflip) dst_rect.size.y=-dst_rect.size.y; texture->draw_rect_region(ci,dst_rect,src_rect,modulate); } break; } }
Common::Rect Surface::render(Graphics::Surface *surface, int dx, int dy, bool mirror, Common::Rect src_rect, uint zoom) const { if (src_rect.isEmpty()) { src_rect = Common::Rect(0, 0, w, h); } Common::Rect dst_rect(x + dx, y + dy, x + dx + zoom * src_rect.width() / 256, y + dy + zoom * src_rect.height() / 256); if (dst_rect.left < 0) { src_rect.left = -dst_rect.left; dst_rect.left = 0; } if (dst_rect.right > surface->w) { src_rect.right -= dst_rect.right - surface->w; dst_rect.right = surface->w; } if (dst_rect.top < 0) { src_rect.top -= dst_rect.top; dst_rect.top = 0; } if (dst_rect.bottom > surface->h) { src_rect.bottom -= dst_rect.bottom - surface->h; dst_rect.bottom = surface->h; } if (src_rect.isEmpty() || dst_rect.isEmpty()) return Common::Rect(); if (zoom == 256) { const byte *src = (const byte *)getBasePtr(0, src_rect.top); byte *dst_base = (byte *)surface->getBasePtr(dst_rect.left, dst_rect.top); for (int i = src_rect.top; i < src_rect.bottom; ++i) { byte *dst = dst_base; for (int j = src_rect.left; j < src_rect.right; ++j) { byte p = src[(mirror? w - j - 1: j)]; if (p != 0xff) *dst++ = p; else ++dst; } dst_base += surface->pitch; src += pitch; } } else { byte *dst = (byte *)surface->getBasePtr(dst_rect.left, dst_rect.top); for(int i = 0; i < dst_rect.height(); ++i) { for (int j = 0; j < dst_rect.width(); ++j) { int px = j * 256 / zoom; const byte *src = (const byte *)getBasePtr(src_rect.left + (mirror? w - px - 1: px), src_rect.top + i * 256 / zoom); byte p = *src; if (p != 0xff) dst[j] = p; } dst += surface->pitch; } } return dst_rect; }
void shiftMat(InputArray _src, OutputArray _dst, const Point shift) { Mat src = _src.getMat(); _dst.create(src.size(), src.type()); Mat dst = _dst.getMat(); Mat res = Mat::zeros(src.size(), src.type()); int width = src.cols - abs(shift.x); int height = src.rows - abs(shift.y); Rect dst_rect(max(shift.x, 0), max(shift.y, 0), width, height); Rect src_rect(max(-shift.x, 0), max(-shift.y, 0), width, height); src(src_rect).copyTo(res(dst_rect)); res.copyTo(dst); }
/* ================================================================ 画像のαブレンド ※リトルエンディアン環境を仮定 ================================================================ */ void VnImage::Blend(const VnImage& img, u_int8_t srcAlpha, const VnRect& srcRect, int dx, int dy) { // 範囲内のチェック(これは共通ルーチンにした方が良い:TODO:) VnRect src_rect(0, 0, img.Width(), img.Height()); src_rect &= srcRect; VnRect dst_rect(0, 0, Width(), Height()); dst_rect &= VnRect(dx, dy, src_rect.width, src_rect.height); VnTime t(true); int alpha_table[256 * 2 - 1]; for(int a = -255; a < 256; ++a) { if (a < 0) { alpha_table[a + 255] = -((-a * srcAlpha) >> 8); } else {
void AnimatedSprite::_notification(int p_what) { switch(p_what) { case NOTIFICATION_DRAW: { if (frames.is_null()) return; if (frame<0 || frame>=frames->get_frame_count()) return; Ref<Texture> texture = frames->get_frame(frame); if (texture.is_null()) return; //print_line("DECIDED TO DRAW"); RID ci = get_canvas_item(); /* texture->draw(ci,Point2()); break; */ Size2i s; s = texture->get_size(); Point2 ofs=offset; if (centered) ofs-=s/2; Rect2 dst_rect(ofs,s); if (hflip) dst_rect.size.x=-dst_rect.size.x; if (vflip) dst_rect.size.y=-dst_rect.size.y; texture->draw_rect(ci,dst_rect,false,modulate); // VisualServer::get_singleton()->canvas_item_add_texture_rect_region(ci,dst_rect,texture->get_rid(),src_rect,modulate); } break; } }
void Window_BattleStatus::DrawGauge(Game_Actor* /* actor */, int index, int cx, int cy) { BitmapRef system2 = Cache::System2(Data::system.system2_name); Battle::Ally& ally = Game_Battle::GetAlly(index); bool full = ally.IsReady(); int gauge_w = ally.gauge * 25 / Game_Battle::gauge_full; int speed = 2; // FIXME: how to determine? int gauge_y = 32 + speed * 16; Rect gauge_left(0, gauge_y, 16, 16); Rect gauge_center(16, gauge_y, 16, 16); Rect gauge_right(32, gauge_y, 16, 16); Rect gauge_bar(full ? 64 : 48, gauge_y, 16, 16); Rect dst_rect(cx+16, cy, 25, 16); Rect bar_rect(cx+16, cy, gauge_w, 16); contents->Blit(cx+0, cy, *system2, gauge_left, 255); contents->StretchBlit(dst_rect, *system2, gauge_center, 255); contents->Blit(cx+16+25, cy, *system2, gauge_right, 255); contents->StretchBlit(bar_rect, *system2, gauge_bar, 255); }
/* ================================================================ 指定した矩形内の各画素(RGB各成分)に対し,各成分ごとに指定した値を 加/減する。引数の範囲は一般的には -256 〜 +256だろうが、その範囲外でも 動作する。 (※リトルエンディアン環境を仮定) 計算結果の各成分が…… 0以下 : 0でクランプ 256以上 : 255でクランプ ================================================================ */ void VnImage::Add(int r, int g, int b, const VnRect& rect) { VnRect dst_rect(0, 0, Width(), Height()); dst_rect &= rect; for(int y = 0; y < dst_rect.height; ++y) { u_int32_t* dst = GetPixelBuf(dst_rect.x, dst_rect.y + y); for(int x = 0; x < dst_rect.width; ++x, ++dst) { int dr = ( *dst & 0xff) + r; int dg = ((*dst >> 8) & 0xff) + g; int db = ((*dst >> 16) & 0xff) + b; dr = (dr < 0) ? 0 : (dr > 256) ? 255 : dr; dg = (dg < 0) ? 0 : (dg > 256) ? 255 : dg; db = (db < 0) ? 0 : (db > 256) ? 255 : db; *dst = (dr | (dg << 8) | (db << 16)); } } }
void Direct3D11::renderText() { if ( ! font_ ) { return; } getSprite()->begin(); EffectTechnique* technique = effect_->get_technique( "|sprite" ); for ( const auto& pass : technique->get_pass_list() ) { pass->apply(); Sprite::Rect dst_rect( 0, 0, get_width(), get_height() ); getSprite()->draw( dst_rect, text_view_.get() ); } getSprite()->end(); }
/** * 指定したイメージ(img)の特定の成分(RGBAのどれか)をαとみなし, それをコピー * * @param img 転送元 * @param mask pixelに対するマスク * @param shift 右シフト値。α = (ToInterfaceColor(pixel) & mask) >> shift; * @param srcRect 転送元 * @param dx 転送先 * @param dy 転送先 */ void VnImage::CopyAlpha(const VnImage& img, const u_int32_t mask, const u_int32_t shift, const VnRect& srcRect, int dx, int dy) { // 範囲内のチェック VnRect src_rect(0, 0, img.Width(), img.Height()); src_rect &= srcRect; VnRect dst_rect(0, 0, Width(), Height()); dst_rect &= VnRect(dx, dy, src_rect.width, src_rect.height); for(int y = 0; y < dst_rect.height; ++y) { const u_int32_t* src = img.GetPixelBuf(src_rect.x, src_rect.y + y); u_int32_t* dst = GetPixelBuf(dst_rect.x, dst_rect.y + y); for(int x = 0; x < dst_rect.width; ++x, ++dst, ++src) { int a = (ToInterfaceColor(*src) & mask) >> shift; int r = ( *dst & 0xff); int g = ((*dst >> 8) & 0xff); int b = ((*dst >> 16) & 0xff); *dst = r | (g << 8) | (b << 16) | (a << 24); } } }
void TBFontFace::DrawString(int x, int y, const TBColor &color, const char *str, int len) { if (m_bgFont) m_bgFont->DrawString(x+m_bgX, y+m_bgY, m_bgColor, str, len); if (m_font_renderer) g_renderer->BeginBatchHint(TBRenderer::BATCH_HINT_DRAW_BITMAP_FRAGMENT); int i = 0; while (str[i] && i < len) { UCS4 cp = utf8::decode_next(str, &i, len); if (cp == 0xFFFF) continue; if (TBFontGlyph *glyph = GetGlyph(cp, true)) { if (glyph->frag) { TBRect dst_rect(x + glyph->metrics.x, y + glyph->metrics.y + GetAscent(), glyph->frag->Width(), glyph->frag->Height()); TBRect src_rect(0, 0, glyph->frag->Width(), glyph->frag->Height()); if (glyph->has_rgb) g_renderer->DrawBitmap(dst_rect, src_rect, glyph->frag); else g_renderer->DrawBitmapColored(dst_rect, src_rect, color, glyph->frag); } x += glyph->metrics.advance; } else if (!m_font_renderer) // This is the test font. Use same glyph width as height and draw square. { g_renderer->DrawRect(TBRect(x, y, m_metrics.height / 3, m_metrics.height), color); x += m_metrics.height / 3 + 1; } } if (m_font_renderer) g_renderer->EndBatchHint(); }
/* ================================================================ 塗りつぶし。 αが0xff以外の時は, 各RGBに対して目標値と現在のピクセルとでαブレンディングする (※リトルエンディアンを仮定) ================================================================ */ void VnImage::Fill(u_int32_t color, const VnRect& rect) { const u_int8_t r = GetRed(color); const u_int8_t g = GetGreen(color); const u_int8_t b = GetBlue(color); const u_int8_t a = GetAlpha(color); VnRect dst_rect(0, 0, Width(), Height()); dst_rect &= rect; if (a == 0xff) { const u_int32_t fill_color = ToMachineColor(color); // cerr << "Fill: " << hex << fill_color << dec << endl; // 不透明塗りつぶし for(int y = 0; y < dst_rect.height; ++y) { u_int32_t* dst = GetPixelBuf(dst_rect.x, dst_rect.y + y); for(int x = 0; x < dst_rect.width; ++x, ++dst) { *dst = fill_color; } } } else { // αブレンディング for(int y = 0; y < dst_rect.height; ++y) { u_int32_t* dst = GetPixelBuf(dst_rect.x, dst_rect.y + y); for(int x = 0; x < dst_rect.width; ++x, ++dst) { // よりよい最適化は後回し // リトルエンディアンの場合, 0xAABBGGRRとなる const int dr = ((r - ( *dst & 0xff)) * a) >> 8; const int dg = ((g - ((*dst >> 8) & 0xff)) * a) >> 8; const int db = ((b - ((*dst >> 16) & 0xff)) * a) >> 8; *dst += (dr | (dg << 8) | (db << 16)); } } } }
/** * \brief Draws a subrectangle of this surface on another surface. * \param region The subrectangle to draw in this object. * \param dst_surface The destination surface. * \param dst_position Coordinates on the destination surface. * The width and height of this rectangle are ignored. */ void Surface::raw_draw_region( const Rectangle& region, Surface& dst_surface, const Rectangle& dst_position) { if (dst_surface.software_destination // The destination surface is in RAM. || !Video::is_acceleration_enabled() // The rendering is in RAM. ) { if (dst_surface.internal_surface == NULL) { dst_surface.create_software_surface(); } // First, draw subsurfaces if any. // They can exist if the video mode recently switched from an accelerated // one to a software one. if (!subsurfaces.empty()) { if (this->internal_surface == NULL) { create_software_surface(); } std::vector<SubSurfaceNode*> subsurfaces = this->subsurfaces; this->subsurfaces.clear(); // Avoid infinite recursive calls if there are cycles. std::vector<SubSurfaceNode*>::const_iterator it; const std::vector<SubSurfaceNode*>::const_iterator end = subsurfaces.end(); for (it = subsurfaces.begin(); it != end; ++it) { SubSurfaceNode* subsurface = *it; // TODO draw the subsurfaces of the whole tree recursively instead. // The current version is not correct because it handles only one level // (it ignores subsurface->subsurfaces). // Plus it needs the workaround above to avoid a stack overflow. subsurface->src_surface->raw_draw_region( subsurface->src_rect, *this, subsurface->dst_rect ); RefCountable::unref(subsurface); } clear_subsurfaces(); } if (this->internal_surface != NULL) { // The source surface is not empty: draw it onto the destination. SDL_BlitSurface( this->internal_surface, region.get_internal_rect(), dst_surface.internal_surface, Rectangle(dst_position).get_internal_rect() ); } else if (internal_color != NULL) { // No internal surface to draw: this may be a color. if (internal_color->get_internal_color()->a == 255) { // Fill with opaque color: we can directly modify the destination pixels. Rectangle dst_rect( dst_position.get_x(), dst_position.get_y(), region.get_width(), region.get_height() ); SDL_FillRect( dst_surface.internal_surface, dst_rect.get_internal_rect(), this->internal_color->get_internal_value() ); } else { // Fill with semi-transparent pixels: perform alpha-blending. create_software_surface(); SDL_FillRect( this->internal_surface, NULL, this->internal_color->get_internal_value() ); SDL_BlitSurface( this->internal_surface, region.get_internal_rect(), dst_surface.internal_surface, Rectangle(dst_position).get_internal_rect() ); } } } else { // The destination is a GPU surface (a texture). // Do not draw anything, just store the operation in the tree instead. // The actual drawing will be done at rendering time in GPU. dst_surface.add_subsurface(*this, region, dst_position); } dst_surface.is_rendered = false; }
void AnimatedSprite3D::_draw() { RID immediate = get_immediate(); VS::get_singleton()->immediate_clear(immediate); if (!frames.is_valid() || !frames->get_frame_count(animation) || frame<0 || frame>=frames->get_frame_count(animation)) { return; } Ref<Texture> texture = frames->get_frame(animation,frame); if (!texture.is_valid()) return; //no texuture no life Vector2 tsize = texture->get_size(); if (tsize.x==0 || tsize.y==0) return; Size2i s=tsize; Rect2i src_rect; src_rect.size=s; Point2i ofs=get_offset(); if (is_centered()) ofs-=s/2; Rect2i dst_rect(ofs,s); Rect2 final_rect; Rect2 final_src_rect; if (!texture->get_rect_region(dst_rect,src_rect,final_rect,final_src_rect)) return; if (final_rect.size.x==0 || final_rect.size.y==0) return; Color color=_get_color_accum(); color.a*=get_opacity(); float pixel_size=get_pixel_size(); Vector2 vertices[4]={ (final_rect.pos+Vector2(0,final_rect.size.y)) * pixel_size, (final_rect.pos+final_rect.size) * pixel_size, (final_rect.pos+Vector2(final_rect.size.x,0)) * pixel_size, final_rect.pos * pixel_size, }; Vector2 uvs[4]={ final_src_rect.pos / tsize, (final_src_rect.pos+Vector2(final_src_rect.size.x,0)) / tsize, (final_src_rect.pos+final_src_rect.size) / tsize, (final_src_rect.pos+Vector2(0,final_src_rect.size.y)) / tsize, }; if (is_flipped_h()) { SWAP(uvs[0],uvs[1]); SWAP(uvs[2],uvs[3]); } if (is_flipped_v()) { SWAP(uvs[0],uvs[3]); SWAP(uvs[1],uvs[2]); } Vector3 normal; int axis = get_axis(); normal[axis]=1.0; RID mat = VS::get_singleton()->material_2d_get(get_draw_flag(FLAG_SHADED),get_draw_flag(FLAG_TRANSPARENT),get_alpha_cut_mode()==ALPHA_CUT_DISCARD,get_alpha_cut_mode()==ALPHA_CUT_OPAQUE_PREPASS); VS::get_singleton()->immediate_set_material(immediate,mat); VS::get_singleton()->immediate_begin(immediate,VS::PRIMITIVE_TRIANGLE_FAN,texture->get_rid()); int x_axis = ((axis + 1) % 3); int y_axis = ((axis + 2) % 3); if (axis!=Vector3::AXIS_Z) { SWAP(x_axis,y_axis); for(int i=0;i<4;i++) { //uvs[i] = Vector2(1.0,1.0)-uvs[i]; //SWAP(vertices[i].x,vertices[i].y); if (axis==Vector3::AXIS_Y) { vertices[i].y = - vertices[i].y; } else if (axis==Vector3::AXIS_X) { vertices[i].x = - vertices[i].x; } } } AABB aabb; for(int i=0;i<4;i++) { VS::get_singleton()->immediate_normal(immediate,normal); VS::get_singleton()->immediate_color(immediate,color); VS::get_singleton()->immediate_uv(immediate,uvs[i]); Vector3 vtx; vtx[x_axis]=vertices[i][0]; vtx[y_axis]=vertices[i][1]; VS::get_singleton()->immediate_vertex(immediate,vtx); if (i==0) { aabb.pos=vtx; aabb.size=Vector3(); } else { aabb.expand_to(vtx); } } set_aabb(aabb); VS::get_singleton()->immediate_end(immediate); }
void AnimatedSprite::_notification(int p_what) { switch (p_what) { case NOTIFICATION_INTERNAL_PROCESS: { if (frames.is_null()) return; if (!frames->has_animation(animation)) return; if (frame < 0) return; float speed = frames->get_animation_speed(animation); if (speed == 0) return; //do nothing float remaining = get_process_delta_time(); while (remaining) { if (timeout <= 0) { timeout = 1.0 / speed; int fc = frames->get_frame_count(animation); if (frame >= fc - 1) { if (frames->get_animation_loop(animation)) { frame = 0; } else { frame = fc - 1; } } else { frame++; if (frame == fc - 1) { emit_signal(SceneStringNames::get_singleton()->animation_finished); } } update(); _change_notify("frame"); emit_signal(SceneStringNames::get_singleton()->frame_changed); } float to_process = MIN(timeout, remaining); remaining -= to_process; timeout -= to_process; } } break; case NOTIFICATION_DRAW: { if (frames.is_null()) { print_line("no draw no faemos"); return; } if (frame < 0) { print_line("no draw frame <0"); return; } if (!frames->has_animation(animation)) { print_line("no draw no anim: " + String(animation)); return; } Ref<Texture> texture = frames->get_frame(animation, frame); if (texture.is_null()) { print_line("no draw texture is null"); return; } Ref<Texture> normal = frames->get_normal_frame(animation, frame); //print_line("DECIDED TO DRAW"); RID ci = get_canvas_item(); /* texture->draw(ci,Point2()); break; */ Size2i s; s = texture->get_size(); Point2 ofs = offset; if (centered) ofs -= s / 2; if (Engine::get_singleton()->get_use_pixel_snap()) { ofs = ofs.floor(); } Rect2 dst_rect(ofs, s); if (hflip) dst_rect.size.x = -dst_rect.size.x; if (vflip) dst_rect.size.y = -dst_rect.size.y; //texture->draw_rect(ci,dst_rect,false,modulate); texture->draw_rect_region(ci, dst_rect, Rect2(Vector2(), texture->get_size()), Color(1, 1, 1), false, normal); //VisualServer::get_singleton()->canvas_item_add_texture_rect_region(ci,dst_rect,texture->get_rid(),src_rect,modulate); } break; } }
/** * \brief Draws a subrectangle of this surface on another surface. * \param region The subrectangle to draw in this object. * \param dst_surface The destination surface. * \param dst_position Coordinates on the destination surface. */ void Surface::raw_draw_region( const Rectangle& region, Surface& dst_surface, const Point& dst_position) { if (dst_surface.software_destination // The destination surface is in RAM. || !Video::is_acceleration_enabled() // The rendering is in RAM. ) { if (dst_surface.internal_surface == nullptr) { dst_surface.create_software_surface(); } // First, draw subsurfaces if any. // They can exist if the video mode recently switched from an accelerated // one to a software one. if (!subsurfaces.empty()) { if (this->internal_surface == nullptr) { create_software_surface(); } std::vector<SubSurfaceNodePtr> subsurfaces = this->subsurfaces; this->subsurfaces.clear(); // Avoid infinite recursive calls if there are cycles. for (SubSurfaceNodePtr& subsurface: subsurfaces) { // TODO draw the subsurfaces of the whole tree recursively instead. // The current version is not correct because it handles only one level // (it ignores subsurface->subsurfaces). // Plus it needs the workaround above to avoid a stack overflow. subsurface->src_surface->raw_draw_region( subsurface->src_rect, *this, subsurface->dst_rect.get_xy() ); subsurface = nullptr; } clear_subsurfaces(); } if (this->internal_surface != nullptr) { // The source surface is not empty: draw it onto the destination. SDL_SetSurfaceBlendMode( this->internal_surface.get(), get_sdl_blend_mode() ); SDL_BlitSurface( this->internal_surface.get(), region.get_internal_rect(), dst_surface.internal_surface.get(), Rectangle(dst_position).get_internal_rect() ); } else if (internal_color != nullptr) { // No internal surface to draw: this may be a color. if (get_blend_mode() == BlendMode::BLEND && internal_color->get_alpha() == 255) { // Fill with opaque color: we can directly modify the destination pixels. Rectangle dst_rect( dst_position, region.get_size() ); SDL_FillRect( dst_surface.internal_surface.get(), dst_rect.get_internal_rect(), get_color_value(*internal_color) ); } else { // Fill with semi-transparent pixels: perform alpha-blending. create_software_surface(); SDL_FillRect( this->internal_surface.get(), nullptr, get_color_value(*internal_color) ); SDL_BlitSurface( this->internal_surface.get(), region.get_internal_rect(), dst_surface.internal_surface.get(), Rectangle(dst_position).get_internal_rect() ); } } } else { // The destination is a GPU surface (a texture). // Do not draw anything, just store the operation in the tree instead. // The actual drawing will be done at rendering time in GPU. SurfacePtr src_surface = std::static_pointer_cast<Surface>(shared_from_this()); dst_surface.add_subsurface(src_surface, region, dst_position); } dst_surface.is_rendered = false; }
void AnimatedSprite::_notification(int p_what) { switch (p_what) { case NOTIFICATION_INTERNAL_PROCESS: { if (frames.is_null()) return; if (!frames->has_animation(animation)) return; if (frame < 0) return; float speed = frames->get_animation_speed(animation) * speed_scale; if (speed == 0) return; //do nothing float remaining = get_process_delta_time(); while (remaining) { if (timeout <= 0) { timeout = _get_frame_duration(); int fc = frames->get_frame_count(animation); if (frame >= fc - 1) { if (frames->get_animation_loop(animation)) { frame = 0; emit_signal(SceneStringNames::get_singleton()->animation_finished); } else { frame = fc - 1; if (!is_over) { is_over = true; emit_signal(SceneStringNames::get_singleton()->animation_finished); } } } else { frame++; } update(); _change_notify("frame"); emit_signal(SceneStringNames::get_singleton()->frame_changed); } float to_process = MIN(timeout, remaining); remaining -= to_process; timeout -= to_process; } } break; case NOTIFICATION_DRAW: { if (frames.is_null()) return; if (frame < 0) return; if (!frames->has_animation(animation)) return; Ref<Texture> texture = frames->get_frame(animation, frame); if (texture.is_null()) return; Ref<Texture> normal = frames->get_normal_frame(animation, frame); RID ci = get_canvas_item(); Size2i s; s = texture->get_size(); Point2 ofs = offset; if (centered) ofs -= s / 2; if (Engine::get_singleton()->get_use_pixel_snap()) { ofs = ofs.floor(); } Rect2 dst_rect(ofs, s); if (hflip) dst_rect.size.x = -dst_rect.size.x; if (vflip) dst_rect.size.y = -dst_rect.size.y; texture->draw_rect_region(ci, dst_rect, Rect2(Vector2(), texture->get_size()), Color(1, 1, 1), false, normal); } break; } }
void Sprite3D::_draw() { RID immediate = get_immediate(); VS::get_singleton()->immediate_clear(immediate); if (!texture.is_valid()) return; //no texuture no life Vector2 tsize = texture->get_size(); if (tsize.x == 0 || tsize.y == 0) return; Size2i s; Rect2i src_rect; if (region) { s = region_rect.size; src_rect = region_rect; } else { s = texture->get_size(); s = s / Size2i(hframes, vframes); src_rect.size = s; src_rect.position.x += (frame % hframes) * s.x; src_rect.position.y += (frame / hframes) * s.y; } Point2i ofs = get_offset(); if (is_centered()) ofs -= s / 2; Rect2i dst_rect(ofs, s); Rect2 final_rect; Rect2 final_src_rect; if (!texture->get_rect_region(dst_rect, src_rect, final_rect, final_src_rect)) return; if (final_rect.size.x == 0 || final_rect.size.y == 0) return; Color color = _get_color_accum(); color.a *= get_opacity(); float pixel_size = get_pixel_size(); Vector2 vertices[4] = { (final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size, (final_rect.position + final_rect.size) * pixel_size, (final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size, final_rect.position * pixel_size, }; Vector2 src_tsize = tsize; // Properly setup UVs for impostor textures (AtlasTexture). Ref<AtlasTexture> atlas_tex = texture; if (atlas_tex != NULL) { src_tsize[0] = atlas_tex->get_atlas()->get_width(); src_tsize[1] = atlas_tex->get_atlas()->get_height(); } Vector2 uvs[4] = { final_src_rect.position / src_tsize, (final_src_rect.position + Vector2(final_src_rect.size.x, 0)) / src_tsize, (final_src_rect.position + final_src_rect.size) / src_tsize, (final_src_rect.position + Vector2(0, final_src_rect.size.y)) / src_tsize, }; if (is_flipped_h()) { SWAP(uvs[0], uvs[1]); SWAP(uvs[2], uvs[3]); } if (is_flipped_v()) { SWAP(uvs[0], uvs[3]); SWAP(uvs[1], uvs[2]); } Vector3 normal; int axis = get_axis(); normal[axis] = 1.0; RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS); VS::get_singleton()->immediate_set_material(immediate, mat); VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_TRIANGLE_FAN, texture->get_rid()); int x_axis = ((axis + 1) % 3); int y_axis = ((axis + 2) % 3); if (axis != Vector3::AXIS_Z) { SWAP(x_axis, y_axis); for (int i = 0; i < 4; i++) { //uvs[i] = Vector2(1.0,1.0)-uvs[i]; //SWAP(vertices[i].x,vertices[i].y); if (axis == Vector3::AXIS_Y) { vertices[i].y = -vertices[i].y; } else if (axis == Vector3::AXIS_X) { vertices[i].x = -vertices[i].x; } } } AABB aabb; for (int i = 0; i < 4; i++) { VS::get_singleton()->immediate_normal(immediate, normal); VS::get_singleton()->immediate_color(immediate, color); VS::get_singleton()->immediate_uv(immediate, uvs[i]); Vector3 vtx; vtx[x_axis] = vertices[i][0]; vtx[y_axis] = vertices[i][1]; VS::get_singleton()->immediate_vertex(immediate, vtx); if (i == 0) { aabb.position = vtx; aabb.size = Vector3(); } else { aabb.expand_to(vtx); } } set_aabb(aabb); VS::get_singleton()->immediate_end(immediate); }
void Sprite3D::_draw() { RID immediate = get_immediate(); VS::get_singleton()->immediate_clear(immediate); if (!texture.is_valid()) return; //no texuture no life Vector2 tsize = texture->get_size(); if (tsize.x==0 || tsize.y==0) return; Size2i s; Rect2i src_rect; if (region) { s=region_rect.size; src_rect=region_rect; } else { s = texture->get_size(); s=s/Size2i(hframes,vframes); src_rect.size=s; src_rect.pos.x+=(frame%hframes)*s.x; src_rect.pos.y+=(frame/hframes)*s.y; } Point2i ofs=get_offset(); if (is_centered()) ofs-=s/2; Rect2i dst_rect(ofs,s); Rect2 final_rect; Rect2 final_src_rect; if (!texture->get_rect_region(dst_rect,src_rect,final_rect,final_src_rect)) return; if (final_rect.size.x==0 || final_rect.size.y==0) return; Color color=_get_color_accum(); color.a*=get_opacity(); float pixel_size=get_pixel_size(); Vector2 vertices[4]={ (final_rect.pos+Vector2(0,final_rect.size.y)) * pixel_size, (final_rect.pos+final_rect.size) * pixel_size, (final_rect.pos+Vector2(final_rect.size.x,0)) * pixel_size, final_rect.pos * pixel_size, }; Vector2 uvs[4]={ final_src_rect.pos / tsize, (final_src_rect.pos+Vector2(final_src_rect.size.x,0)) / tsize, (final_src_rect.pos+final_src_rect.size) / tsize, (final_src_rect.pos+Vector2(0,final_src_rect.size.y)) / tsize, }; if (is_flipped_h()) { SWAP(uvs[0],uvs[1]); SWAP(uvs[2],uvs[3]); } if (is_flipped_v()) { SWAP(uvs[0],uvs[3]); SWAP(uvs[1],uvs[2]); } Vector3 normal; int axis = get_axis(); normal[axis]=1.0; RID mat = VS::get_singleton()->material_2d_get(get_draw_flag(FLAG_SHADED),get_draw_flag(FLAG_TRANSPARENT),get_alpha_cut_mode()==ALPHA_CUT_DISCARD,get_alpha_cut_mode()==ALPHA_CUT_OPAQUE_PREPASS); VS::get_singleton()->immediate_set_material(immediate,mat); VS::get_singleton()->immediate_begin(immediate,VS::PRIMITIVE_TRIANGLE_FAN,texture->get_rid()); int x_axis = ((axis + 1) % 3); int y_axis = ((axis + 2) % 3); AABB aabb; for(int i=0;i<4;i++) { VS::get_singleton()->immediate_normal(immediate,normal); VS::get_singleton()->immediate_color(immediate,color); VS::get_singleton()->immediate_uv(immediate,uvs[i]); Vector3 vtx; vtx[x_axis]=vertices[i][x_axis]; vtx[y_axis]=vertices[i][y_axis]; VS::get_singleton()->immediate_vertex(immediate,vtx); if (i==0) { aabb.pos=vtx; aabb.size=Vector3(); } else { aabb.expand_to(vtx); } } set_aabb(aabb); VS::get_singleton()->immediate_end(immediate); }
void AnimatedSprite::_notification(int p_what) { switch(p_what) { case NOTIFICATION_PROCESS: { if (frames.is_null()) return; if (!frames->has_animation(animation)) return; if (frame<0) return; float speed = frames->get_animation_speed(animation) * play_rate; if (speed==0) return; //do nothing float remaining = get_process_delta_time(); while(remaining) { if (timeout<=0) { int fc = frames->get_frame_count(animation); if (frame>=fc-1) { if (frames->get_animation_loop(animation)) { frame=0; } else { frame=fc-1; // early exit so we don't do anything for non-looping ended animations, may want to // broadcast once more "frame" notify, pending break; } } else { frame++; } // to avoid timeout being reset for non-looping animations so queries can be use timeout value timeout = 1.0 / speed; update(); _change_notify("frame"); } float to_process = MIN(timeout,remaining); remaining-=to_process; timeout-=to_process; } } break; case NOTIFICATION_DRAW: { if (frames.is_null()) { print_line("no draw no faemos"); return; } if (frame<0) { print_line("no draw frame <0"); return; } if (!frames->has_animation(animation)) { print_line("no draw no anim: "+String(animation)); return; } Ref<Texture> texture = frames->get_frame(animation,frame); if (texture.is_null()) { print_line("no draw texture is null"); return; } //print_line("DECIDED TO DRAW"); RID ci = get_canvas_item(); /* texture->draw(ci,Point2()); break; */ Size2i s; s = texture->get_size(); Point2 ofs=offset; adjust_offset(ofs, s); if (OS::get_singleton()->get_use_pixel_snap()) { ofs=ofs.floor(); } Rect2 dst_rect(ofs,s); if (hflip) dst_rect.size.x=-dst_rect.size.x; if (vflip) dst_rect.size.y=-dst_rect.size.y; //texture->draw_rect(ci,dst_rect,false,modulate); texture->draw_rect_region(ci,dst_rect,Rect2(Vector2(),texture->get_size()),modulate); // VisualServer::get_singleton()->canvas_item_add_texture_rect_region(ci,dst_rect,texture->get_rid(),src_rect,modulate); } break; } }