diff --git a/binding/bitmap-binding.cpp b/binding/bitmap-binding.cpp index 2df48453..36a04a13 100644 --- a/binding/bitmap-binding.cpp +++ b/binding/bitmap-binding.cpp @@ -663,7 +663,7 @@ RB_METHOD(bitmapGetLooping){ Bitmap *b = getPrivateData(self); bool ret; - GUARD_EXC(b->getLooping();); + GUARD_EXC(ret = b->getLooping();); return rb_bool_new(ret); } @@ -671,12 +671,14 @@ RB_METHOD(bitmapGetLooping){ RB_METHOD(bitmapSnapToBitmap) { RB_UNUSED_PARAM; - rb_check_argc(argc, 0); + VALUE position; + rb_scan_args(argc, argv, "01", &position); Bitmap *b = getPrivateData(self); Bitmap *newbitmap = 0; - GUARD_EXC(newbitmap = new Bitmap(*b, false);); + int pos = (position == RUBY_Qnil) ? -1 : NUM2INT(position); + GUARD_EXC(newbitmap = new Bitmap(*b, pos);); VALUE ret = rb_obj_alloc(rb_class_of(self)); diff --git a/src/display/bitmap.cpp b/src/display/bitmap.cpp index 37fc0e48..6789a563 100644 --- a/src/display/bitmap.cpp +++ b/src/display/bitmap.cpp @@ -637,16 +637,29 @@ Bitmap::Bitmap(void *pixeldata, int width, int height) p->addTaintedArea(rect()); } -Bitmap::Bitmap(const Bitmap &other, bool copyAllFrames) +// frame is -2 for "any and all", -1 for "current", anything else for a specific frame +Bitmap::Bitmap(const Bitmap &other, int frame) { other.ensureNonMega(); + if (frame > -2) other.ensureAnimated(); p = new BitmapPrivate(this); - if (!other.isAnimated() || !copyAllFrames) { - other.ensureNotPlaying(); + if (!other.isAnimated() || frame >= -1) { + if (frame == -1) other.ensureNotPlaying(); p->gl = shState->texPool().request(other.width(), other.height()); - blt(0, 0, other, rect()); + + GLMeta::blitBegin(p->gl); + // Blit just the current frame of the other animated bitmap + if (frame == -1) { + GLMeta::blitSource(other.getGLTypes()); + } + else { + auto &frames = other.getFrames(); + GLMeta::blitSource(frames[clamp(frame, 0, (int)frames.size() - 1)]); + } + GLMeta::blitRectangle(rect(), rect(), true); + GLMeta::blitEnd(); } else { p->animation.enabled = true; @@ -657,10 +670,10 @@ Bitmap::Bitmap(const Bitmap &other, bool copyAllFrames) p->animation.loop = other.getLooping(); char *tmp = new char[p->animation.width * p->animation.height * 4]; - for (const TEXFBO &frame : other.getFrames()) { - TEXFBO copyframe; + for (TEXFBO &sourceframe : other.getFrames()) { + TEXFBO newframe; try { - copyframe = shState->texPool().request(p->animation.width, p->animation.height); + newframe = shState->texPool().request(p->animation.width, p->animation.height); } catch(const Exception &e) { for (TEXFBO &f : p->animation.frames) shState->texPool().release(f); @@ -668,17 +681,17 @@ Bitmap::Bitmap(const Bitmap &other, bool copyAllFrames) throw e; } - // FIXME: gotta see if I can copy textures directly from one TEXFBO to the other - // I'm an idiot so I don't already know - FBO::bind(frame.fbo); - gl.ReadPixels(0,0,p->animation.width,p->animation.height,GL_RGBA,GL_UNSIGNED_BYTE,tmp); - TEX::bind(copyframe.tex); - TEX::uploadImage(p->animation.width, p->animation.height, tmp, GL_RGBA); + GLMeta::blitBegin(newframe); + GLMeta::blitSource(sourceframe); + GLMeta::blitRectangle(rect(), rect(), true); + GLMeta::blitEnd(); - p->animation.frames.push_back(copyframe); + p->animation.frames.push_back(newframe); } delete[] tmp; } + + p->addTaintedArea(rect()); } Bitmap::~Bitmap() @@ -859,7 +872,7 @@ void Bitmap::stretchBlt(const IntRect &destRect, { /* Fast blit */ GLMeta::blitBegin(getGLTypes()); - GLMeta::blitSource(getGLTypes()); + GLMeta::blitSource(source.getGLTypes()); GLMeta::blitRectangle(sourceRect, destRect); GLMeta::blitEnd(); } @@ -1770,7 +1783,7 @@ void Bitmap::setInitFont(Font *value) p->font = value; } -TEXFBO &Bitmap::getGLTypes() +TEXFBO &Bitmap::getGLTypes() const { return (p->animation.enabled) ? p->animation.currentFrame() : p->gl; } @@ -1801,6 +1814,14 @@ void Bitmap::ensureNonAnimated() const GUARD_ANIMATED; } +void Bitmap::ensureAnimated() const +{ + if (isDisposed()) + return; + + GUARD_UNANIMATED; +} + void Bitmap::ensureNotPlaying() const { if (isDisposed()) @@ -1899,14 +1920,10 @@ int Bitmap::addFrame(Bitmap &source, int position) p->surface = 0; } else { - // FIXME: gotta see if I can copy textures directly from one TEXFBO to the other - // I'm an idiot so I don't already know - auto pixels = new char[source.width() * source.height() * 4]; - FBO::bind(source.getGLTypes().fbo); - gl.ReadPixels(0,0,source.width(),source.height(),GL_RGBA,GL_UNSIGNED_BYTE,pixels); - TEX::bind(newframe.tex); - TEX::uploadImage(newframe.width, newframe.height, pixels, GL_RGBA); - delete[] pixels; + GLMeta::blitBegin(newframe); + GLMeta::blitSource(source.getGLTypes()); + GLMeta::blitRectangle(rect(), rect(), true); + GLMeta::blitEnd(); } int ret; diff --git a/src/display/bitmap.h b/src/display/bitmap.h index 4fb43a64..70c7443a 100644 --- a/src/display/bitmap.h +++ b/src/display/bitmap.h @@ -42,7 +42,9 @@ public: Bitmap(int width, int height); Bitmap(void *pixeldata, int width, int height); /* Clone constructor */ - Bitmap(const Bitmap &other, bool copyAllFrames = true); + + // frame is -2 for "any and all", -1 for "current", anything else for a specific frame + Bitmap(const Bitmap &other, int frame = -2); ~Bitmap(); int width() const; @@ -114,11 +116,12 @@ public: void setInitFont(Font *value); /* */ - TEXFBO &getGLTypes(); + TEXFBO &getGLTypes() const; SDL_Surface *surface() const; SDL_Surface *megaSurface() const; void ensureNonMega() const; void ensureNonAnimated() const; + void ensureAnimated() const; // Animation functions void stop();