The following code will erase a bitmap (brush akk droplet) from another bitmap (akka
The code works great on PC and pretty ok performacewise.
When i test it on more android devices, it doesn't work. No matter if is a high end device or a slower one. I've made some tests and found out the problem is lock() and unlock() functions from BitmapData. It simply doesn't update the image on device, only once.
I've tried to remove them, but the then it lags alot. Also the performace drop is noticeable on PC too.
Does anyone know a solution, where am I doing wrong?
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.geom.Point;
import flash.events.MouseEvent;
import flash.geom.ColorTransform;
import flash.geom.Rectangle;
var m:BitmapData = new water_pattern;
var b:BitmapData = new droplet;
var bm:Bitmap = new Bitmap(m);
var bla = new blabla();
addChild(bla);
bla.addChild(bm);
function p($x,$y){
var refPoint = new Point($x-b.width/2,$y-b.height/2);
for(var i=0;i<b.width;i++)
for(var j=0;j<b.height;j++)
{
var a:uint = (b.getPixel32(i,j)>> 24) & 0xFF;
a=0xFF-a;
var tp:uint = m.getPixel32(refPoint.x+i,refPoint.y+j);
var tp_trans:uint = (tp >> 24)&0xFF;
if(tp_trans>a){
tp=(tp&0x00FFFFFF)|(a<<24);
m.setPixel32(refPoint.x+i,refPoint.y+j,tp);
}
}
//for(var k=0;k<10000000;k++){};
}
var k=1;
var md = function(e)
{
m.lock();
p(bm.mouseX,bm.mouseY);
m.unlock();
};
bla.addEventListener(MouseEvent.MOUSE_DOWN,function(e)
{
bla.addEventListener(Event.EXIT_FRAME,md);
});
bla.addEventListener(MouseEvent.MOUSE_UP,function(e)
{
bla.removeEventListener(Event.EXIT_FRAME,md);
});
I've reworked the code :
public function draw($x, $y)
{
var refPoint = new Point($x - brush.width / 2, $y - brush.height / 2);
var r:Rectangle = new Rectangle(refPoint.x, refPoint.y, brush.width, brush.height);
var pv:Vector.<uint> = pattern.getVector(r);
var bv:Vector.<uint> = brush.getVector(brush.rect);
for (var i = 0; i < bv.length; i++)
{
var a:uint = (bv[i]>>24) &0xFF;
a = 0xFF - a;
var tp:uint = pv[i];
var tp_trans:uint = (tp >> 24) & 0xFF;
// trace(a.toString(16) + " vs " + tp_trans.toString(16));
if (tp_trans > a)
{
tp = (tp & 0x00FFFFFF) | (a << 24);
// trace("??>" + tp);
pv[i] = tp;
}
}
pattern.setVector(r, pv);
}
Now it works, but still it is pretty slow on device. That before i saw Jeff Ward's comment, so i changed it to render mode on CPU. It works fast.
The big problem is in CPU mode the game is very slow compared to GPU. Yet this script is fast on CPU but unusable slow on GPU.
So I've tried again the first code and surprise. It works. Jeff Ward, thank you, you're a genius.
Now the question remains is why? Can someone please explain?
For your original question, sometimes GPU mode doesn't pick up changes into the underlying bitmapdata. Try any one of these operations after your unlock() to 'hint' that it should re-upload the bitmap data:
bm.filters = [];
bm.bitmapData = m;
bm.alpha = 0.98+Math.random()*0.02;
But as you found, uploading bitmapdata can be slow. To clarify GPU/direct render modes:
In GPU mode, changing any pixel in a Bitmap requires a re-upload of the full bitmap, so it's the size of Bitmap that's the limiting factor. In direct mode, it blits only the portions of the screen that have been updated. So I'd guess some parts of the game change a lot of the screen at once (slow in direct mode), whereas this effect changes a large bitmap, but only a little bit at a time (slow in GPU mode).
You have to get creative to maximize your performance wrt GPUs:
In GPU mode, split the effect into many bitmaps, and only change as few as possible for any given frame. (medium effort)
Use Starling GPU-accelerated framework and Starling filters (GPU shaders) to achieve your effect (effort depends on how much you have invested in your game already), see a couple of examples
Related
After struggling a few hours on making my app detect this QRCode:
I realized that the problem was the in the QRCode appearance. After inverting the colors, the detection was working perfectly..
Is there a way to make Vision API detect the first QRCode? I tried to enable all symbologies but it did not work. I guess it is possible because the app QR Code Reader detects it.
I improved googles example app "barcode-reader" to detect both inverted colored barcodes and regular ones.
here is a link to googles example app:
https://github.com/googlesamples/android-vision/tree/master/visionSamples/barcode-reader
I did so by editing "CameraSource" class,
package: "com.google.android.gms.samples.vision.barcodereader.ui.camera".
I added a parameter: private boolean isInverted = false;
and changed function void setNextFrame(byte[] data, Camera camera):
void setNextFrame(byte[] data, Camera camera) {
synchronized (mLock) {
if (mPendingFrameData != null) {
camera.addCallbackBuffer(mPendingFrameData.array());
mPendingFrameData = null;
}
if (!mBytesToByteBuffer.containsKey(data)) {
Log.d(TAG,
"Skipping frame. Could not find ByteBuffer associated with the image " +
"data from the camera.");
return;
}
mPendingTimeMillis = SystemClock.elapsedRealtime() - mStartTimeMillis;
mPendingFrameId++;
if (!isInverted){
for (int y = 0; y < data.length; y++) {
data[y] = (byte) ~data[y];
}
isInverted = true;
} else {
isInverted = false;
}
mPendingFrameData = mBytesToByteBuffer.get(data);
// Notify the processor thread if it is waiting on the next frame (see below).
mLock.notifyAll();
}
}
I think this is still an open issue, please see link for details. One workaround for this as stated by a developer:
Right, the barcode API generally doesn't support color-inverted codes. There's no parameter or option to control this at the moment. Though some APIs support them, I don't believe it's a common feature.
For a workaround, you could preprocess the colors in the bitmap before passing them to the barcode API (perhaps inverting colors on alternate frames).
Hope this helps.
First of all, I saw an existing question (JCIFS: file retrieval is too slow to be usable), but it was for Java, not Android, and none of the suggested answers worked.
I created a default project for Android SDK 25 (7.1.1) in Android Studio 2.3, linked the library with compile 'jcifs:jcifs:1.3.17', and typed the following simple test code. The result is below the code.
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
jcifs.Config.setProperty("jcifs.util.loglevel", "3");
//jcifs.Config.setProperty("jcifs.smb.client.dfs.disabled", "false");
//jcifs.Config.setProperty("jcifs.resolveOrder", "DNS");
try
{
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("", ID, PASSWORD);
final SmbFile smb = new SmbFile("smb://192.168.XX.XX/Share/FileName", auth);
Thread t = new Thread(new Runnable()
{
#Override
public void run()
{
Log.d(TAG, "Test Start");
for(int i = 1000; i<10000; i+=1000)
measure(i);
Log.d(TAG, "Test End");
}
private void measure(int bufferSize)
{
Log.d(TAG, "=====Buffer: " + bufferSize + "============");
try
{
byte[] buffer = new byte[bufferSize];
int read = 0;
InputStream str = smb.getInputStream();
long start = System.nanoTime();
while(read < 1000000)
read += str.read(buffer);
long end = System.nanoTime();
str.close();
float time = (float) ((end - start) / 1000000000d);
float speed = (float) read / 1048576 / time;
Log.d(TAG, "Time:" + time + ", size =" + read);
Log.d(TAG, "Speed = " + speed + "MB/s");
}
catch(IOException exc)
{
exc.printStackTrace();
}
}
});
t.start();
}
catch(Exception exc)
{
Log.d(TAG, exc.toString());
}
}
Result
Test Start
=====Buffer: 1000============
Time:2.210785, size =1000000
Speed = 0.43137363MB/s
=====Buffer: 2000============
Time:1.4158936, size =1000000
Speed = 0.6735495MB/s
=====Buffer: 3000============
Time:1.0556641, size =1002000
Speed = 0.9051948MB/s
=====Buffer: 4000============
Time:0.7543335, size =1000000
Speed = 1.2642609MB/s
=====Buffer: 5000============
Time:3.6557617, size =1000000
Speed = 0.26086885MB/s
=====Buffer: 6000============
Time:3.292389, size =1002000
Speed = 0.2902396MB/s
=====Buffer: 7000============
Time:2.9179688, size =1001000
Speed = 0.32715496MB/s
=====Buffer: 8000============
Time:2.462616, size =1000000
Speed = 0.38726068MB/s
=====Buffer: 9000============
Time:3.9379272, size =1008000
Speed = 0.24411413MB/s
Test End
Read speed is about 0.2MB/s ~ 1.2MB/s. The device is connected to a 150Mbps Wi-Fi, so, theoretically it can achieve above 10MB/s. The SMB server is not slow either. When I copied the file to a laptop, the read speed was about 30MB/s.
Why is this so slow? What should I check? Why is the read speed about 5 times higher (1.2MB/s) if the buffer size is 4000?
By the way, I have tested copying the same file with other commercial apps. File Commander, Asus File Manager showed similary low speed, ES File Explorer showed about 2MB/s, and Solid Explorer showed about 5MB/s. Since I am pretty sure that all of them use JCIFS (albeit perhaps slightly different versions of it), there must be a way to achieve at least 5MB/s as Solid Explorer does.
After using WireShark (network analysis tool) on the Windows computer, I have found that no matter which buffer size I set, the read SMB command always gives 4286 bytes to the Windows computer. It seems that SmbFileInputStream.java is using the max buffer size from the server.
But when I saw the packets from Soild Explorer, it was 32768 bytes. So, I decompiled Solid Explorer's APK (it was of course obfuscated), and saw the SmbFileInputStream.java file inside of it (that file belongs to JCIFS). It seems that the developers of Solid Explorer has modified that file, and set a bigger readSize. So, I tried a similar thing. And then I achieved 5MB/s for the same code above.
Since JCIFS comes with LGPL, the fact that Solid Explorer is using a modified JCIFS without disclosing the source code is a violation of JCIFS' licence. But, oh well, it seems a lot of Android app developers ignores licence of the libraries they use anyway. They do not even properly credit the open-source libraries they used.
Did you try with: jcifs.Config.setProperty("jcifs.smb.client.dfs.disabled", "true");
In my case (though Java) it was helpful for slow connection. By default it is false
Only problem for me is that I'm not sure will that property "break" something else which is working fine..
There is a patch for large buffer size reading:
https://github.com/kohsuke/jcifs/issues/11
https://github.com/kohsuke/jcifs/tree/master/patches
https://jcifs.samba.org/src/patches/LargeReadWrite.patch:
From inside the README:
This patch adds two SMBs that supposedly improves read and write
performance considerably. Unfortunately it's not crystal clear that
all implementation properly support the commands. Note that in
addition to this patch an '& 0xFFFF' needs to be added in
SmbTransport.java:doRecv:~437 to appear as:
int size = Encdec.dec_uint16be( BUF, 2 ) & 0xFFFF;
although this change has been made in 1.2.7.
Not sure if this works with Android, but the solution could be similar.
i am having issues with speed of communication between workers in AS3 coding for AIR for android. my test device is a Galaxy S2 (android 4.0.4) and i am developing in flashdevelop using AIR18.0.
first things first.
i tried the good old AMF serialisation copying via shared object. i was getting smack average 49 calculations/second on the physics engine (the secondary thread) with a stable 60FPS on main thread. had to crank it up over to over 300 dynamic objects to get any noticeable slowdown.
all went well, so i started the on-device testing and that is when shit started to go sideways. i was getting less than 1.5 steps/s.
started to dig a bit deeper, write a shitton of code to check what the hell is so slow and i found that looking at shared objects was kinda like watching other people watching paint dry.
at this point i started to get deeper into researching. i found that there are a number of people already complaining about the speed of message channels (found not much on shared objects, "developers" status quo i guess). so i decided to go the lowest i could using shared bytearrays and mutexes. (i skipped over condition since i don't particularly want any of my threads to pause).
cranked up the desktop debugger i was getting 115-ish calculations/s and over 350 calculations/s with direct callback (the debugger did throw the exception, wasn't designed for that kind of continuous processing i guess.. anywho..). shared bytearray and mutexes was as advertised, faster than the orgasm of my ex girlfriend.
i do the debugging on the S2 and behold, i get 3.4 calculations/s with 200 dynamic objects.
so.. concurrency on mobile was pretty much done for me. then i thought i do a little test with no communication whatsoever. same scene, physics doing a more than acceptable 40 calculations/s and graphics running at the expected 60FPS...
so, my bluntly evident question:
WHAT the FAPPING FIREFLY is going on?
here is my Com code:
package CCom
{
import Box2D.Dynamics.b2Body;
import Box2D.Dynamics.b2World;
import flash.concurrent.Condition;
import flash.concurrent.Mutex;
import flash.utils.ByteArray;
import Grx.DickbutImage;
import Phx.PhxMain;
/**
* shared and executed across all threads.
* provides access to mutex and binary data.
*
* #author szeredai akos
*/
public class CComCore
{
//===============================================================================================//
public static var positionData:ByteArray = new ByteArray();
public static var positionMutex:Mutex = new Mutex();
public static var creationData:ByteArray = new ByteArray();
public static var creationMutex:Mutex = new Mutex();
public static var debugData:ByteArray = new ByteArray();
public static var debugMutex:Mutex = new Mutex();
//===============================================================================================//
public function CComCore()
{
positionData.shareable = true;
creationData.shareable = true;
debugData.shareable = true;
}
//===============================================================================================//
public static function encodePositions(w:b2World):void
{
var ud:Object;
positionMutex.lock();
positionData.position = 0;
for (var b:b2Body = w.GetBodyList(); b; b = b.GetNext())
{
ud = b.GetUserData();
if (ud && ud.serial)
{
positionMutex.lock();
positionData.writeInt(ud.serial); // serial
positionData.writeBoolean(b.IsAwake); // active state
positionData.writeInt(b.GetType()) // 0-static 1-kinematic 2-dynamic
positionData.writeDouble(b.GetPosition().x / PhxMain.SCALE); // x
positionData.writeDouble(b.GetPosition().y / PhxMain.SCALE); // y
positionData.writeDouble(b.GetAngle()); // r in radians
}
}
positionData.length = positionData.position;
positionMutex.unlock();
}
//===============================================================================================//
public static function decodeToAry(ar:Vector.<DickbutImage>):void
{
var index:int;
var rot:Number = 0;
positionData.position = 0;
while (positionData.bytesAvailable > 0)
{
//positionMutex.lock();
index = positionData.readInt();
positionData.readBoolean();
positionData.readInt();
ar[index].x -= (ar[index].x - positionData.readDouble()) / 10;
ar[index].y -= (ar[index].y - positionData.readDouble()) / 10;
ar[index].rotation = positionData.readDouble();
//positionMutex.unlock();
}
}
//===============================================================================================//
}
}
(disregard the lowpass filter on the position y-=(y-x)/c)
so.
please note that having the mutex only on the parsing of the physics does increase performance by about 20% while having minimal impact on the framerate of the main thread. this leads me to believe that the problem does not lie in the writing and reading of the data per say but in the speed at which that data is made available for a second thread. i mean,.. those are bytearray ops, it's only natural that it is fast. i did check the speed by simply dumping the remote thread into the main, and the speed is still sound. hell,.. it gets acceptable even on the S2 without dumping the extra calculations.
ps: i did try release version too.
if no one has a viable solution (besides a .2-.4s buffer, and the obvious single thread) i do want to hear about wanky workarounds or at least the specific source of the problem.
thx in advance
Think I found the issue.
As always things are more complex than one initially thinks.
Timer events, as well as set interval and timeout are all limited to 60fps. The timer does execute on time as long as the app is idle at that particular point or IMMEDIATELY after it is free to execute and the delay has passed. But the delay, obviously, can't be shorter than 15-ish (and its less on desktop, I guess). Shouldn't be a problem, right?
However.
If that piece of code manipulates shared objects the timer suddenly decides to shit himself and look at it for those 15ms regardless if it had its idle time or not.
Anyhow, the thing is that there is an buggy interaction between shared objects, workers, timer events and the adobe imposed 60FPS limitation.
The workaround is quite simple. Have the timer on some massive delay of like 5000ms and do like 5000 loops within the callback of the timer event. Obviously, the next timer event won't fire until the 5000loop is completed but most importantly it also won't add that monumental delay.
Another weird thing that came up is the greedy ownership of mutexes during the 5000loop so the usage of flash.concurrent.Condition is a must.
The good thing is that the performance boost is there and its impressive.
The downside is that the entire physics thing is now intimately locked to the framerate of the main thread (or whatever contraption the main game loop consists of), but hey. 60Fps is good enough, I guess.
Zi MuleTrex-Condition thing for those interested:
package CCom
{
import Box2D.Dynamics.b2Body;
import Box2D.Dynamics.b2World;
import flash.concurrent.Condition;
import flash.concurrent.Mutex;
import flash.utils.ByteArray;
import Grx.DickbutImage;
import Phx.PhxMain;
/**
* shared and executed across all threads.
* provides access to mutex and binary data.
*
* #author szeredai akos
*/
public class CComCore
{
//===============================================================================================//
public static var positionData:ByteArray = new ByteArray();
public static var positionMutex:Mutex = new Mutex();
public static var positionCondition:Condition = new Condition(positionMutex);
public static var creationData:ByteArray = new ByteArray();
public static var creationMutex:Mutex = new Mutex();
public static var debugData:ByteArray = new ByteArray();
public static var debugMutex:Mutex = new Mutex();
//===============================================================================================//
public function CComCore()
{
positionData.shareable = true;
creationData.shareable = true;
debugData.shareable = true;
}
//===============================================================================================//
public static function encodePositions(w:b2World):void
{
var ud:Object;
positionData.position = 0;
positionMutex.lock();
for (var b:b2Body = w.GetBodyList(); b; b = b.GetNext())
{
ud = b.GetUserData();
if (ud && ud.serial)
{
positionData.writeBoolean(b.IsAwake); // active state
positionData.writeInt(ud.serial); // serial
positionData.writeInt(b.GetType()) // 0-static 1-kinematic 2-dynamic
positionData.writeDouble(b.GetPosition().x / PhxMain.SCALE); // x
positionData.writeDouble(b.GetPosition().y / PhxMain.SCALE); // y
positionData.writeDouble(b.GetAngle()); // r in radians
}
}
positionData.writeBoolean(false);
positionCondition.wait();
}
//===============================================================================================//
public static function decodeToAry(ar:Vector.<DickbutImage>):void
{
var index:int;
var rot:Number = 0;
positionMutex.lock();
positionData.position = 0;
while (positionData.bytesAvailable > 0 && positionData.readBoolean())
{
//positionMutex.lock();
index = positionData.readInt();
positionData.readInt();
ar[index].x = positionData.readDouble();
ar[index].y = positionData.readDouble();
ar[index].rotation = positionData.readDouble();
//positionMutex.unlock();
}
positionCondition.notify();
positionMutex.unlock();
}
//===============================================================================================//
}
}
Sync will become a lot more complex as more channels and byteArrays start to pop up.
My enemy script is linked to a prefab and being instantiated by my main script.
It kills enemies in a random order (I am jumping on them and some are not dying, not what I want).
(what I am trying to achieve is an enemy to die when I jump on its head and play a death animation.
So from this enemy script I call the other script jump <-- which is linked to my player script and get the jump Boolean value. Could the processing of jump be to slow? I need help
I tried everything)
it works but only on certain enemies any ideas why? Thanks community.
Can anyone help me find a better method?
Could someone help me maybe find if the Players y => an amount to change jump var on the enemy
Just had a perfect run, whats wrong with this its working then not then it is partly working
If I add audio, it doesn't work.
#pragma strict
var enemy : GameObject;
var speed : float = 1.0;
var enemanim : Animator;
var isdying : boolean = false;
private var other : main;
var playerhit: boolean = false;
function Start () {
other = GameObject.FindWithTag("Player").GetComponent("main");
this.transform.position.x = 8.325;
this.transform.position.y = -1.3;
enemanim = GetComponent(Animator);
enemanim.SetFloat("isdead",0);
}
function OnCollisionEnter2D(coll: Collision2D) {
if(coll.gameObject.CompareTag("distroy")){
Destroy(enemy.gameObject);
}
if(coll.gameObject.CompareTag("Player")){
playerhit=true;
}
}
function Update () {
if(other.jumped === true && playerhit==true){ *****the jumped i need
enemanim.SetFloat("isdead",1);
}
}
function FixedUpdate(){
this.transform.Translate(Vector3(Input.GetAxis("Horizontal") * speed * Time.deltaTime, 0, 0));
this.rigidbody2D.velocity = Vector2(-5,0);
}
if(other.jumped === true && playerhit==true)
Is wrong.
It should be:
if(other.jumped == true && playerhit==true)
All 3 languages used by Unity, C#, UnityScript, and Boo, are compiled into the same IL byte code at the end. However, there are cases where UnityScript has some overhead as Unity does things in the background. One of these is that it does wrapping of access to members of built-in struct-properties like transform.position.
I prefer C#, I think it is better.
Making an AS3 app for android that uses camera roll to load, select and then use an image.
The cameraroll browser works fine, but when the image is selected, the app crashes - almost every time - as it has worked on a handful of occasions (!?!) We assumed a memory issue and attempted to close all other windows / use smaller photos in the camera roll etc. and try different devices - but cannot recreate success consistently. Cannot find another ANE that works either
It fails at the point where the photo has been selected, and RESTARTS the app...
here's the relevant code, any help appreciated.
public function openGallery():void {
var cameraRoll:CameraRoll = new CameraRoll();
if(CameraRoll.supportsBrowseForImage) {
cameraRoll.addEventListener(MediaEvent.SELECT, imageSelected);
cameraRoll.addEventListener(flash.events.Event.CANCEL, browseCanceled);
cameraRoll.addEventListener(flash.events.ErrorEvent.ERROR, mediaError);
cameraRoll.browseForImage();
}
else { trace( "Image browsing is not supported on this device."); }
}
private function imageSelected(event:MediaEvent):void {
trace("Media selected...");
var imagePromise:MediaPromise = event.data as MediaPromise;
_dataSource = imagePromise.open();
if(imagePromise.isAsync) {
trace("Asynchronous media promise.");
var eventSource:IEventDispatcher = _dataSource as IEventDispatcher;
eventSource.addEventListener(flash.events.Event.COMPLETE, onMediaLoaded);
} else {
trace("Synchronous media promise.");
readMediaData();
}
}
private function onMediaLoaded(event:flash.events.Event):void{
trace("Media load complete");
_mediaBytes = new ByteArray();
_dataSource.readBytes(_mediaBytes);
_tempDir = File.createTempDirectory();
var now:Date = new Date();
var filename:String;
filename = now.fullYear + now.month + now.day+now.hours + now.minutes + now.seconds + ".JPG";
_file = _tempDir.resolvePath(filename);
//writing temporal file to display image
_stream = new FileStream();
_stream.open(_file,FileMode.WRITE);
_stream.writeBytes(_mediaBytes);
_stream.close();
if(_file.exists){
_imageLoader = new Loader();
_imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,onMediaLoadedBitmapData);
_imageLoader.loadBytes(_mediaBytes);
}
}
private function onMediaLoadedBitmapData(event:Event):void{
trace("onMediaLoadedBitmapData");
var loaderInfo:LoaderInfo = LoaderInfo(event.target);
_bitmapData = new BitmapData(loaderInfo.width,loaderInfo.height,false,0xFFFFFF);
_bitmapData.draw(loaderInfo.loader);
addPictureToScreen();
}
I had a similar thing happen in Air for iOS but it was related to picking large images. I just checked the dimensions of the chosen image and then used a scalar matrix if they were past a certain point. Sounds like you've thought about this but maybe look further into that?