úterý 2. července 2013

IE 10 refuses to download file

Symptoms:
  • Download history (CTRL+J) does not work
  • Downloading any file does not show the download prompt (Open/Save)
  • Clearing Download history using the CTRL+SHIFT+DEL menu does not help
  • Recent update to IE 10
Then try deleting C:\Users\Roman\AppData\Local\Microsoft\Windows\Temporary Internet Files\counters.dat
Internet Explorer was trying to open this file with ACCES_DENIED result. Found using SysInternals Process Monitor.

středa 10. dubna 2013

Masking images on iOS (GLKit edition)

The idea is simple. You have a greyscale (mask) image and an opaque colored image and you want to combine them to an image where black areas from the mask image are transparent. My motivation was to save space when saving transparent images. JPEG is used for the color information and the transparency is restored from the mask. The process is easilly automated with ImageMagick's
convert $file -alpha extract $mask.png

Apple's documentation contains pretty nice articles on image masks, and tells you about the 'CGImageCreateWithMask' that seems to do exactly what you want. But there are two catches. First of all, the masked image should already have alpha channel (well, at least the various sources on the interwebs suggest so). The more important problem is that '[GLKTextureLoader textureWithCGImage: ....]' always dropped the alpha channel.
The solution I used is to create an offscreen Quartz bitmap context, clip it with an image mask, draw the opaque image, create image from the offscreen context and load that one. The other catch I discovered is that GLKTextureLoader ignores endianess information and you have to create the offscreen context with explicit 'kCGBitmapByteOrder32Little' .
Here comes the code. Please note that I am not really an experienced ObjC developer, so do not consider it 'best practices'.
        NSString* maskFile=;
        NSString* dataFile=;
        
        //load data
        CGDataProviderRef dataProvider=CGDataProviderCreateWithFilename([dataFile cStringUsingEncoding:NSASCIIStringEncoding]);
        CGImageRef dataImage=CGImageCreateWithJPEGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault);
        int width=CGImageGetWidth(dataImage);
        int height=CGImageGetHeight(dataImage);
        //load mask
        CGDataProviderRef maskProvider=CGDataProviderCreateWithFilename([maskFile cStringUsingEncoding:NSASCIIStringEncoding]);
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGImageRef maskImage=CGImageCreateWithPNGDataProvider(maskProvider, NULL, false, kCGRenderingIntentDefault);
        //create the masked image
        CGContextRef offscreenContext = CGBitmapContextCreate(NULL, width, height,8,width*4, colorSpace,
                                                              kCGImageAlphaPremultipliedFirst|kCGBitmapByteOrder32Little);
        CGContextClipToMask(offscreenContext, CGRectMake(0,0,width,height), maskImage);
        CGContextDrawImage(offscreenContext, CGRectMake(0, 0, width, height), dataImage);
        CGImageRef resultImage = CGBitmapContextCreateImage(offscreenContext);
        CGContextRelease(offscreenContext);
        
        //CGImageRef resultImage=dataImageWithAlpha;
        NSError* error;
        NSDictionary* opts=[NSDictionary new];
        GLKTextureInfo* info=[GLKTextureLoader textureWithCGImage:resultImage options:opts error:&error];
        if(info==nil){
            NSLog(@"Error during loading image %@. Exception %@ occured.",resultImage,error);
        }
        [opts release];
        //if you are going to load larger images, it might be worth releasing the intermediate images
        //as soon as they are not needed
        CGDataProviderRelease(maskProvider);
        CGDataProviderRelease(dataProvider);
        CGImageRelease(dataImage);
        CGImageRelease(maskImage);
        CGImageRelease(resultImage);
        CGColorSpaceRelease(colorSpace);
        return info;

pondělí 29. srpna 2011

AdbFuseFS

This FUSE filesystem let's you mount your internal device memory. Download distribution tarball at: http://www.mediafire.com/?pxkkbm5hmqap9ya , then ./configure & make & make install. First connect your phone (or emulator). After that you must make sure the adb server is running, so try some eclipse deployment or just run 'adb shell'. You can mount your phone by 'adbfusefs -s <mountpoint>'. If you experience any problems, try runing adbfusefs with -d option.
Current gotchas:
  • when file is opened, it is copied to a temporary directory. Just opening  the /system/ directory in nautilus can take quite a long time, since it tries to fetch previews for all the APKs there
  • advanced file operations (readlink,mv,rm...) are implemented by issuing shell commands. This is only tested with busybox-enabled phone. 
  • Does not call adb command. Adb need not be on your phone, but adb server has to be started. Adbfusefs  uses its sync service directly.
And for those lazy, here comes 32-bit linux binary.

pondělí 28. února 2011

Android NDK the easy(ier) way

There are many Android NDK tutorials out there, but sometimes I feel they do things the hard way, and you end up disgusted, programming in plain old Java again, because getting all that JNI stuff working is so hard. But before you start using NDK, ask first if you really need it. I have found three valid reasons (well, reasons I consider valid, everything depends on your case)
  1. Write once, run everywhere. That is Java's motto, but actually native code is going to run on more devices than your Java. If you write your game proper in C/C++, you automatically have to create some sort of device interface to make it work under android, because in NDK you can not access the Android input and UI APIs (actually 2.3 supports that, but we are going to target 1.6). It is on you, where you draw the line.
  2. Using native libraries. If they have a Java binding, they probably do not have one for Android.
  3. Speed is the least important factor. Not many games are CPU bound and unless you are doing heavy physics simulation, it is not going to be an important factor.
All three points summed up are quite a big reason to write native code.

Simple JNI, the hard way
I assume you can make a sample OpenGL application. Make a simple project in Eclipse with just one activity and GLSurfaceView. The renderer might look similar to this:

public void onSurfaceCreated(GL10 gl, EGLConfig config) 
{
   activity.surfaceCreatedNativeCallback();
}
public void onSurfaceChanged(GL10 gl, int width, int height) 

{
   if(height == 0) {  

      height = 1;
   }
   gl.glViewport(0, 0, width, height);

}
public void onDrawFrame(GL10 gl) {
   gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
}


Let's call our activity cz.badroid.FooActivity. We will define the surfaceNativeCallback like this:
public native void surfaceCreatedNativeCallback();
There is no method body, because, we are going to implement it in native code. Download android NDK and extract it to folder we will call %NDKHOME% from now on. Create a directory called jni in your Eclipse project(on the same level as those src, res directories) and add two files there:
Android.mk:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := yourlibname
LOCAL_SRC_FILES := main.cpp
LOCAL_LDLIBS := -llog -lGLESv1_CM
include $(BUILD_SHARED_LIBRARY)

main.cpp:
#include <GLES/gl.h>
extern "C"{

   JNIEXPORT void JNICALL Java_cz_badroid_FooActivity_surfaceCreatedNativeCallback
      (JNIEnv * env, jobject activity)
   {
         glClearColor(0,0,1,1);
   }
}
Now just build it by running %NDKHOME%/ndk-build in the jni directory. You have just set GL Clear Color in native code! There are common problems and misconeceptions:
  • You need a JNI_OnLoad method. No you do not, but it is recommended, so that you can check if your library is being loaded. 
  • You need to register native methods -- no that's not needed at all.
  • The Android Eclipse project does not depend on the jni libs. That means that whenever you rebuild your NDK project, you also have to make sure your parent Eclipse project is rebuilt. I do it by "touch ../AndroidManifest.xml"
The SWIG way
Just imagine writing a JNI methods for all your engine's methods(and converting all the parameters).... Ufff.... The javah tool will help you a little, but it works the other way around, it generates a native code for Java one.
The answer is SWIG -- Simple Wrapper and Interface Generator. There is also other tool, called gluegen, but it works only for plain C. There is our new set of files(I have not tried to compile them, I hope they work):
main.cpp:
#include "main.h";
#include <GLES/gl.h>
void NativeComponent::testNativeMethod(){
    glClearColor(0,0,1,1);
}
main.h:
#ifndef MAIN_H
#define MAIN_H
class NativeComponent{
   public:
   void testNativeMethod();
};
#endif

Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := yourlibname
LOCAL_SRC_FILES := main.cpp bindings_wrap.cxx
LOCAL_LDLIBS := -llog -lGLESv1_CM
include $(BUILD_SHARED_LIBRARY)
bindings.i:
%module nativecomponent
%{
  /* Includes the header in the wrapper code */
  #include "main.h"
%}
 
/* Parse the header file to generate wrappers */
%include "main.h"
That's it. Now we can generate all the bindings by calling:
swig -c++ -java -package cz.badroid.bindings  -outdir ../src/cz/badroid/bindings/ bindings.i
Now you can do in your Java code: