Friday, December 23, 2011

How to convert HD to QVGA / HVGA

Tools

We need the following programs:
1. Apk Manager (download here).
2. Any text editor (notepad will fit).
3. Ida Pro 5.5 (can be found in the internet, the tracker).
4. Any hex editor (I use UltraEdit).
Now let us think that the game is optimized for screen HVGA / QVGA?
It can be divided into several stages.
Key:
1. Changing the rendering resolution to HVGA / QVGA.
2. Adjustment grid touch screen.
Secondary:
3.

How to

disable the cache (necessary in order to be able to convert introductory video at lower resolution).
4. Assigning a hardware button on any action (required for phones without multitouch).

Before proceeding to any stage of optimization, we need to get to the source code, the original source code, we certainly do not get, but we can get a JAVA-byte code, which is quite to our problem would be enough. For this purpose, we use "Apk Manager".

Install and use a "Apk Manager".

The setup is nothing complicated, just unzip it to any folder. Also recommend that a file Script.bat, located in the folder "Apk Manager", change "set heapy = 64" to a higher value, such as 256 or 512, to prevent problems with large agribusiness files.
Working with "Apk Manager" also does not present difficulties. Required APK file put in folder "place-apk-here-for-modding", run "Script.bat" and the pop up window with green text, press "9 " and "Enter". Less than a minute later, the folder "projects" we unpacked APK file. Packs the same, run "Script.bat", click on "11"," Enter ", the question is whether the APC system? "Hit"n". And in the end, when the APK-packed file, sign it, for that press "12 " and "Enter". As a result, we get in the folder "place-apk-here-for-modding" file with the name signed [the name of the original APK-file].apk. Additionally, about "Apk manager" can be read here.
Further in the text I will miss the description of the process of unpacking / packing APK files.
Also, before you start, I recommend to first review a list of commands JAVA-byte code.
Now you can overstep directly to optimization, for example I will use the game "Modern Combat: Sandstorm".

1. Changing the rendering resolution to HVGA / QVGA.

Most games under

android

, written using OpenGL, an OpenGL permission given by the function "glViewPort", and it will use. The most optimal, I think the function "glViewPort" place in the function "OnDrawFrame". To do this, by looking in the folder "smali", which is located in a folder with raspakovanym APK file, look for a file containing the function "OnDrawFrame". Usually this file is named "GameRenderer.smali" or "[Name Game] Renderer.smali ", in this case, "SandstormRenderer.smali". Open it in Notepad or another text editor and find in it the function "OnDrawFrame".
Here is a fragment of this function.

.method public onDrawFrame(Ljavax/microedition/khronos/opengles/GL10;)V
    .locals 6
    .parameter "gl"
    .prologue
    .line 174
    const-wide/16 v0, 0x0
    .line 177
    .local v0, time:J
    invoke-static {}, Ljava/lang/System;->currentTimeMillis()J
    move-result-wide v0
    .line 179
    invoke-static {}, Lcom/gameloft/android/GAND/GloftMCHP/GLMediaPlayer;->update()V
    .line 180
    invoke-static {}, Lcom/gameloft/android/GAND/GloftMCHP/SandstormRenderer;->nativeRender()V
    .line 186
    const-wide/16 v2, 0x32
    invoke-static {}, Ljava/lang/System;->currentTimeMillis()J
    move-result-wide v4
    sub-long/2addr v4, v0
    sub-long v0, v2, v4
    .line 188
    const-wide/16 v2, 0x0
    cmp-long v2, v0, v2
    if-lez v2, :cond_0
    .line 190
    :try_start_0
    invoke-static {v0, v1}, Ljava/lang/Thread;->sleep(J)V
    :try_end_0
    .catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0
    .line 193
    :cond_0
    :goto_0
    return-void
    .line 190
    :catch_0
    move-exception v2
    goto :goto_0
.end method
In this snippet of code to add the function call "glViewPort", so to obtain, as in the code snippet below.

.method public onDrawFrame(Ljavax/microedition/khronos/opengles/GL10;)V
        .locals 9
    .parameter "gl"
    .prologue
    const/16 v8, 0x1E0
    const/16 v7, 0x140
    const/4 v6, 0x0
    invoke-interface {p1, v6, v6, v8, v7}, Ljavax/microedition/khronos/opengles/GL10;->glViewport(IIII)V
    .line 174
    const-wide/16 v0, 0x0
    .line 177
    .local v0, time:J
    invoke-static {}, Ljava/lang/System;->currentTimeMillis()J
    move-result-wide v0
    .line 179
    invoke-static {}, Lcom/gameloft/android/GAND/GloftMCHP/GLMediaPlayer;->update()V
    .line 180
    invoke-static {}, Lcom/gameloft/android/GAND/GloftMCHP/SandstormRenderer;->nativeRender()V
    .line 186
    const-wide/16 v2, 0x32
    invoke-static {}, Ljava/lang/System;->currentTimeMillis()J
    move-result-wide v4
    sub-long/2addr v4, v0
    sub-long v0, v2, v4
    .line 188
    const-wide/16 v2, 0x0
    cmp-long v2, v0, v2
    if-lez v2, :cond_0
    .line 190
    :try_start_0
    invoke-static {v0, v1}, Ljava/lang/Thread;->sleep(J)V
    :try_end_0
    .catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0
    .line 193
    :cond_0
    :goto_0
    return-void
    .line 190
    :catch_0
    move-exception v2
    goto :goto_0
.end method

What we have done here? We've added three constants (v6, v7, v8), assign them a value of coordinates of the left lower (v6; v6) and upper right (v8; v7) corner of the screen and transferred them to the function "glViewport". I think it is understandable why for the coordinates of the lower left corner for the X and Y is used alone and also a constant v6? Since both X and Y in this corner are equal. In addition, change the 2-th line in the function ". locals 6 " on ". locals 9 ", it determines the number of constants / variables used in functions, so we added 3 constants, 6 +3 = 9. Also note that the names of the constants (v6, v7, v8), are not taken casually, as selected by focusing on already used in the function of the constants. If suddenly someone did not understand, 0x1E0 in decimal would be 480 and 0x140 - 320.

Also pay attention to the function "onSurfaceCreated".

.method public onSurfaceCreated(Ljavax/microedition/khronos/opengles/GL10;Ljavax/microedition/khronos/egl/EGLConfig;)V
    .locals 7
    .parameter "gl"
    .parameter "config"
    .prologue
    const/4 v3, -0x1
    .line 138
    const/4 v0, 0x2
    const-string v1, "SandstormRenderer"
    const-string v2, "onSurfaceCreated"
    invoke-static {v0, v1, v2}, Lcom/gameloft/android/GAND/GloftMCHP/GLDebug;->debugMessage(ILjava/lang/String;Ljava/lang/String;)V
    .line 141
    invoke-direct {p0}, Lcom/gameloft/android/GAND/GloftMCHP/SandstormRenderer;->nativeGetJNIEnv()V
    .line 142
    invoke-static {}, Lcom/gameloft/android/GAND/GloftMCHP/GLResLoader;->init()V
    .line 143
    invoke-static {}, Lcom/gameloft/android/GAND/GloftMCHP/GLMediaPlayer;->init()V
    .line 144
    invoke-static {}, Lcom/gameloft/android/GAND/GloftMCHP/Sandstorm;->nativeInit()V
    .line 146
    :goto_0
    sget v0, Lcom/gameloft/android/GAND/GloftMCHP/SandstormGLSurfaceView;->mDevice_W:I
    if-eq v0, v3, :cond_0
    sget v0, Lcom/gameloft/android/GAND/GloftMCHP/SandstormGLSurfaceView;->mDevice_H:I
    if-ne v0, v3, :cond_1
    .line 149
    :cond_0
    const-wide/16 v0, 0x32
    :try_start_0
    invoke-static {v0, v1}, Ljava/lang/Thread;->sleep(J)V
    :try_end_0
    .catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0
    goto :goto_0
    :catch_0
    move-exception v6
    .local v6, ex:Ljava/lang/Exception;
    invoke-virtual {v6}, Ljava/lang/Exception;->printStackTrace()V
    goto :goto_0
    .line 154
    .end local v6           #ex:Ljava/lang/Exception;
    :cond_1
    sget v1, Lcom/gameloft/android/GAND/GloftMCHP/Sandstorm;->m_bEnableKeyboard:I
    const/4 v2, 0x1
    sget v3, Lcom/gameloft/android/GAND/GloftMCHP/SandstormGLSurfaceView;->mDevice_W:I
    sget v4, Lcom/gameloft/android/GAND/GloftMCHP/SandstormGLSurfaceView;->mDevice_H:I
    sget v5, Lcom/gameloft/android/GAND/GloftMCHP/Sandstorm;->mCurrentLang:I
    move-object v0, p0
    invoke-direct/range {v0 .. v5}, Lcom/gameloft/android/GAND/GloftMCHP/SandstormRenderer;->nativeInit(IIIII)V
    .line 155
    return-void
.end method
 Namely, the code

sget v3, Lcom/gameloft/android/GAND/GloftMCHP/SandstormGLSurfaceView;->mDevice_W:I

sget v4, Lcom/gameloft/android/GAND/GloftMCHP/SandstormGLSurfaceView;->mDevice_H:I

In this code, the variable v3, v4 assigned to the real resolution screen devices, and passed to the function "nativeInit". Since the game is still designed for 480x800 resolution, it is better to have the game thinking that you have a device with this particular resolution. in this code is replaced by


const/16 v3, 0x320

const/16 v4, 0x1E0

If you do not experience problems.
(You can ask and 480h720, since the proportion of screens with 480x800 and 320x480 are different and when "squeeze " the picture is slightly flattened (thanks for the comment G @ sh! sh). But in this case, at the stage of "adjustment grid touch screen", the coefficient must be assumed to be between 800 and between 720 and will it be 1.666666666666667 and 720/480 = 1.5)

For some games, our work is enough and they safely change the permissions on all the graphics you need. To do this again packs APK-file and check the phone as he works. If everything is successful then go to the item "adjustment grid the touch screen. " If not, read on. In our case, with the game Modern Combat: Sandstorm, not everything is smooth, game graphics smashtabirovalas until the required permission, and the menu - no. This means that somewhere in the function is called "glViewPort", and then change the resolution to 480x800. Thus, as in the files "*. smali" function "glViewPort" do not call, you can check by searching, so the case in the library "libsandstorm.so".

The main idea of ​​the next step, remove all calls to library functions "glViewPort".
To analyze the library, we need the "Ida Pro". For convenience, copy "libsandstorm.so" in any folder, run "Ida Pro" and click on "New" button

Then choose "Various files", "Unknown file" and click "OK".

In the window, open the file specify the path to the library "libsandstorm.so" and click "Open. "
In the next window, change the "Processor type" to "ARM processorARM710a", then click "Set" and "Ok ".

If after this, there will be another window with anything, click "OK ". Now you need to wait for the disassembly. This process is quite long, in this you can go to smoke or drink coffee
The fact that reverse engineering is completed, will show a message "The initial autoanalysis has been finished." in the lower box "Output window".

For greater convenience, in this case, click the right mouse button on a blue field, and on the shortcut menu, select "Text view". Moving to the beginning of assembler code for the search for "glViewPort".

Hit the keyboard shortcut "Alt + T" in the dialog box to enter search "glViewPort" and click "OK".

We are interested in function calls "BLX glViewport", "BL glViewport", "B glViewport", "BX glViewport", etc. Any other mentions of "glViewport" we deny press "Ctrl + T" and continue the search.
A necessary place, switch to the "Hex View-A".

Make sure that the function call takes 4 bytes and a "CE F7 D4 E8" (in your case, these figures may be different), it is necessary in order to see what needs to be corrected and do not accidentally overwrite anything extra.

Calling this function we need to drink, for it must be replaced by "CE F7 D4 E8" (in your case, these figures may be different) on "C0 46 C0 46. Remember the address "001F994A" and run the hex editor, I use "UltraEdit". Open it to our library.

In order to move us to the right address, click "Ctrl + G", in the input box will appear "0x001F994A" and click "OK".

Moving, we see that hit where you want, all the hexadecimal code converges to the fact that we saw in "Ida Pro" tab "Hex View-A".

Correcting the "CE F7 D4 E8" on "C0 46 C0 46.

Switches to "Ida Pro" and continue to search for the following calls "glViewPort", there may be several dozen. They have been treated similarly.
When all calls to drink, is preserved. Copy to place a revised "libsandstorm.so". Packs APK-file and set the phone to check. If done correctly, the entire schedule to Decrease the required permission.

0 comments:

Post a Comment