[TUT] optimization games HD for QVGA/HVGA

Search This thread

BPaul

Inactive Recognized Developer
May 9, 2011
2,355
8,117
31
Astana
empireb.ml
Recently, a lot of me in a personal message arrives with a question in about optimizing games for screens HVGA, QVGA. Since this question is relevant to many, I decided to write a short statement. Just want to warn you that every game has its own nuances and using the information described here will likely have to adjust it to suit your particular case, moreover, this statement is mostly true to the games from Gameloft. It is also very desirable to have programming skills, even if it is not under an android. In any case, I hope this statement will be helpful and will help to understand the approximate algorithm of actions. Android platform I started relatively recently, perhaps doing something not quite right / best, to it - the guru of the forum, please do not throw rotten tomatoes, and indicate an error, suggest a better option.

Let's start ...

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.
HTML:
.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.
HTML:
.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".
HTML:
.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
HTML:
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
HTML:
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)
Note
In other games instead of code, maybe something like this
HTML:
invoke-virtual {v0}, Landroid/view/Display;->getWidth()I

move-result v3

invoke-virtual {v0}, Landroid/view/Display;->getHeight()I

move-result v4
Anyway replace it at:
HTML:
const/16 v3, 0x320

const/16 v4, 0x1E0
Or variable names can not v3, v4 and v1, v2. Or nothing at all like it to be, and then change nothing.
Or if problems arise, you can just in case, go looking for all "*. smali" files and replace all function calls "Landroid / view / Display; -> getWidth () I" and "Landroid / view / Display; -> getHeight () I ", suffer from it will not.
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
Welcome_to_IDA.png

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

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 ".
Load_a_new_file.png

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 :D
The fact that reverse engineering is completed, will show a message "The initial autoanalysis has been finished." in the lower box "Output window".
Dism1.png

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".
Dism2.png

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

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".
VP1.png

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.
VP2.png

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.
UE1.png

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

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".
UE2.png

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

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.
 
Last edited:

BPaul

Inactive Recognized Developer
May 9, 2011
2,355
8,117
31
Astana
empireb.ml
Continuing the theme of optimizing HD games under HVGA / QVGA

2. Adjustment grid touchscreen

Even when we have optimized the graphic screen HVGA / QVGA and all the buttons on the screen displayed in the right places on the grid touch screen they are on the old field, off screen.
It looks like this.
HVGA_WVGA.png

1 - This is the current place of drawing a button.
2 - An old place of rendering the button and the current location of the buttons on the touch-screen grid.
Fix is quite simple, you need to make sure that when touching the screen at the point 1, the game thought that the touch at point 2. For this to count as a changed, as a result of the previous stage, the coordinates drawn on-screen buttons. To find out, we need to calculate the ratio of how many times the screen resolution HVGA / QVGA less WVGA.
HTML:
[B]For HVGA[/B]
X: 800/480=1,666666666666667
Y: 480/320=1,5
[B]For QVGA[/B]
X: 800/320=2.5
Y: 480/240=2
Therefore if the coordinates of the buttons on the WVGA screen, for example, were 700h360, then HVGA screen, it already coordinates will 420h240 (700 / 1.666666666666667 = 420, 360 / 1,5 = 240). This pattern holds for the other buttons on the screen.
That is our task to make sure that when a player touches the coordinates 420h240 game thought he was touched in the coordinates 700h360.
From this it is understandable that only the coordinates of the touch screen to multiply X by 1,666666666666667, Y 1,5 to HVGA screen and X by 2.5, Y 2 to QVGA.
We'll do it in the event handler touchscreen "onTouchEvent". With the search we find that it is in the files "GameInstaller.smali" and "Sandstorm.smali". We want someone who is in the file "Sandstorm.smali".
HTML:
.method public onTouchEvent(Landroid/view/MotionEvent;)Z
    .locals 10
    .parameter "event"

    .prologue
    const/4 v9, 0x1

    const/4 v8, 0x0

    .line 379
    invoke-virtual {p1}, Landroid/view/MotionEvent;->getAction()I

    move-result v0

    .line 380
    .local v0, action:I
    and-int/lit16 v4, v0, 0xff

    .line 382
    .local v4, mask:I
    invoke-virtual {p1}, Landroid/view/MotionEvent;->getPointerCount()I

    move-result v1

    .line 383
    .local v1, count:I
    const v6, 0xff00

    and-int/2addr v6, v0

    shr-int/lit8 v5, v6, 0x8

    .line 388
    .local v5, pointerId:I
    if-nez v0, :cond_0

    .line 390
    invoke-virtual {p1, v8}, Landroid/view/MotionEvent;->getX(I)F

    move-result v6

    float-to-int v6, v6

    invoke-virtual {p1, v8}, Landroid/view/MotionEvent;->getY(I)F

    move-result v7

    float-to-int v7, v7

    invoke-direct {p0, v6, v7, v8}, Lcom/gameloft/android/GAND/GloftMCHP/Sandstorm;->nativeTouchPressed(III)V

    .line 394
    :cond_0
    const/4 v6, 0x5

    if-ne v4, v6, :cond_1

    .line 397
    invoke-virtual {p1, v5}, Landroid/view/MotionEvent;->getX(I)F

    move-result v6

    float-to-int v6, v6

    invoke-virtual {p1, v5}, Landroid/view/MotionEvent;->getY(I)F

    move-result v7

    float-to-int v7, v7

    invoke-direct {p0, v6, v7, v5}, Lcom/gameloft/android/GAND/GloftMCHP/Sandstorm;->nativeTouchPressed(III)V

    .line 400
    :cond_1
    const/4 v6, 0x2

    if-ne v0, v6, :cond_2

    .line 402
    const/4 v2, 0x0

    .local v2, i:I
    :goto_0
    if-ge v2, v1, :cond_2

    .line 403
    invoke-virtual {p1, v2}, Landroid/view/MotionEvent;->getPointerId(I)I

    move-result v3

    .line 405
    .local v3, id:I
    invoke-virtual {p1, v3}, Landroid/view/MotionEvent;->getX(I)F

    move-result v6

    float-to-int v6, v6

    invoke-virtual {p1, v3}, Landroid/view/MotionEvent;->getY(I)F

    move-result v7

    float-to-int v7, v7

    invoke-direct {p0, v6, v7, v3}, Lcom/gameloft/android/GAND/GloftMCHP/Sandstorm;->nativeTouchMoved(III)V

    .line 402
    add-int/lit8 v2, v2, 0x1

    goto :goto_0

    .line 409
    .end local v2           #i:I
    .end local v3           #id:I
    :cond_2
    const/4 v6, 0x6

    if-ne v4, v6, :cond_3

    .line 412
    invoke-virtual {p1, v5}, Landroid/view/MotionEvent;->getX(I)F

    move-result v6

    float-to-int v6, v6

    invoke-virtual {p1, v5}, Landroid/view/MotionEvent;->getY(I)F

    move-result v7

    float-to-int v7, v7

    invoke-direct {p0, v6, v7, v5}, Lcom/gameloft/android/GAND/GloftMCHP/Sandstorm;->nativeTouchReleased(III)V

    .line 415
    :cond_3
    if-ne v0, v9, :cond_4

    .line 416
    const/4 v2, 0x0

    .restart local v2       #i:I
    :goto_1
    if-ge v2, v1, :cond_4

    .line 418
    invoke-virtual {p1, v2}, Landroid/view/MotionEvent;->getPointerId(I)I

    move-result v3

    .line 421
    .restart local v3       #id:I
    invoke-virtual {p1, v3}, Landroid/view/MotionEvent;->getX(I)F

    move-result v6

    float-to-int v6, v6

    invoke-virtual {p1, v3}, Landroid/view/MotionEvent;->getY(I)F

    move-result v7

    float-to-int v7, v7

    invoke-direct {p0, v6, v7, v3}, Lcom/gameloft/android/GAND/GloftMCHP/Sandstorm;->nativeTouchReleased(III)V

    .line 416
    add-int/lit8 v2, v2, 0x1

    goto :goto_1

    .line 427
    .end local v2           #i:I
    .end local v3           #id:I
    :cond_4
    return v9
.end method
We draw attention to the function
HTML:
invoke-virtual {p1, v5}, Landroid/view/MotionEvent;->getX(I)F

invoke-virtual {p1, v5}, Landroid/view/MotionEvent;->getY(I)F
These functions and define the coordinates of touching the touch screen, immediately after them, we multiply the coordinates on an already calculated coefficients.
For HVGA should get it.
HTML:
.method public onTouchEvent(Landroid/view/MotionEvent;)Z
    .locals 10
    .parameter "event"

    .prologue
    const/4 v9, 0x1

    const/4 v8, 0x0

    .line 379
    invoke-virtual {p1}, Landroid/view/MotionEvent;->getAction()I

    move-result v0

    .line 380
    .local v0, action:I
    and-int/lit16 v4, v0, 0xff

    .line 382
    .local v4, mask:I
    invoke-virtual {p1}, Landroid/view/MotionEvent;->getPointerCount()I

    move-result v1

    .line 383
    .local v1, count:I
    const v6, 0xff00

    and-int/2addr v6, v0

    shr-int/lit8 v5, v6, 0x8

    .line 388
    .local v5, pointerId:I
    if-nez v0, :cond_0

    .line 390
    invoke-virtual {p1, v8}, Landroid/view/MotionEvent;->getX(I)F

    move-result v6

    float-to-int v6, v6

    mul-int/lit8 v6, v6, 0xa

    div-int/lit8 v6, v6, 0x6

    invoke-virtual {p1, v8}, Landroid/view/MotionEvent;->getY(I)F

    move-result v7

    float-to-int v7, v7

    mul-int/lit8 v7, v7, 0x3

    div-int/lit8 v7, v7, 0x2

    invoke-direct {p0, v6, v7, v8}, Lcom/gameloft/android/GAND/GloftMCHP/Sandstorm;->nativeTouchPressed(III)V

    .line 394
    :cond_0
    const/4 v6, 0x5

    if-ne v4, v6, :cond_1

    .line 397
    invoke-virtual {p1, v5}, Landroid/view/MotionEvent;->getX(I)F

    move-result v6

    float-to-int v6, v6

    mul-int/lit8 v6, v6, 0xa

    div-int/lit8 v6, v6, 0x6

    invoke-virtual {p1, v5}, Landroid/view/MotionEvent;->getY(I)F

    move-result v7

    float-to-int v7, v7

    mul-int/lit8 v7, v7, 0x3

    div-int/lit8 v7, v7, 0x2

    invoke-direct {p0, v6, v7, v5}, Lcom/gameloft/android/GAND/GloftMCHP/Sandstorm;->nativeTouchPressed(III)V

    .line 400
    :cond_1
    const/4 v6, 0x2

    if-ne v0, v6, :cond_2

    .line 402
    const/4 v2, 0x0

    .local v2, i:I
    :goto_0
    if-ge v2, v1, :cond_2

    .line 403
    invoke-virtual {p1, v2}, Landroid/view/MotionEvent;->getPointerId(I)I

    move-result v3

    .line 405
    .local v3, id:I
    invoke-virtual {p1, v3}, Landroid/view/MotionEvent;->getX(I)F

    move-result v6

    float-to-int v6, v6

    mul-int/lit8 v6, v6, 0xa

    div-int/lit8 v6, v6, 0x6

    invoke-virtual {p1, v3}, Landroid/view/MotionEvent;->getY(I)F

    move-result v7

    float-to-int v7, v7

    mul-int/lit8 v7, v7, 0x3

    div-int/lit8 v7, v7, 0x2

    invoke-direct {p0, v6, v7, v3}, Lcom/gameloft/android/GAND/GloftMCHP/Sandstorm;->nativeTouchMoved(III)V

    .line 402
    add-int/lit8 v2, v2, 0x1

    goto :goto_0

    .line 409
    .end local v2           #i:I
    .end local v3           #id:I
    :cond_2
    const/4 v6, 0x6

    if-ne v4, v6, :cond_3

    .line 412
    invoke-virtual {p1, v5}, Landroid/view/MotionEvent;->getX(I)F

    move-result v6

    float-to-int v6, v6

    mul-int/lit8 v6, v6, 0xa

    div-int/lit8 v6, v6, 0x6

    invoke-virtual {p1, v5}, Landroid/view/MotionEvent;->getY(I)F

    move-result v7

    float-to-int v7, v7

    mul-int/lit8 v7, v7, 0x3

    div-int/lit8 v7, v7, 0x2

    invoke-direct {p0, v6, v7, v5}, Lcom/gameloft/android/GAND/GloftMCHP/Sandstorm;->nativeTouchReleased(III)V

    .line 415
    :cond_3
    if-ne v0, v9, :cond_4

    .line 416
    const/4 v2, 0x0

    .restart local v2       #i:I
    :goto_1
    if-ge v2, v1, :cond_4

    .line 418
    invoke-virtual {p1, v2}, Landroid/view/MotionEvent;->getPointerId(I)I

    move-result v3

    .line 421
    .restart local v3       #id:I
    invoke-virtual {p1, v3}, Landroid/view/MotionEvent;->getX(I)F

    move-result v6

    float-to-int v6, v6

    mul-int/lit8 v6, v6, 0xa

    div-int/lit8 v6, v6, 0x6

    invoke-virtual {p1, v3}, Landroid/view/MotionEvent;->getY(I)F

    move-result v7

    float-to-int v7, v7

    mul-int/lit8 v7, v7, 0x3

    div-int/lit8 v7, v7, 0x2

    invoke-direct {p0, v6, v7, v3}, Lcom/gameloft/android/GAND/GloftMCHP/Sandstorm;->nativeTouchReleased(III)V

    .line 416
    add-int/lit8 v2, v2, 0x1

    goto :goto_1

    .line 427
    .end local v2           #i:I
    .end local v3           #id:I
    :cond_4
    return v9
.end method
Here is the code that we added to the function
HTML:
mul-int/lit8 v6, v6, 0xa

div-int/lit8 v6, v6, 0x6

...

mul-int/lit8 v7, v7, 0x3

div-int/lit8 v7, v7, 0x2
I hope everyone understood that multiplying by 10 (A in hex​​) and is divided into 6, it is the same as multiply by 1.666666666666667 and multiplying by 3 and dividing by 2 - the same as multiply by 1.5.
Note
In principle, we can proceed a little differently and multiplying the coordinates of the code in the function "onTouchEvent" not to add, instead, to create alternative roles "nativeTouchPressedMod", "nativeTouchMovedMod", "nativeTouchReleasedMod". Replace them, called in "onTouchEvent" original features "nativeTouchPressed", "nativeTouchMoved", "nativeTouchReleased". And in alternate functions to multiply the coordinates and call them with the original function. This is especially useful in those games where instead of a 3-function "nativeTouchPressed", "nativeTouchMoved", "nativeTouchReleased" uses a "nativeOnTouch" (an example of such a game "Hero of Sparta"), there remains a need to create only 1-st alternate function "nativeOnTouchMod", and only in it one must add the code multiplication of coordinates, which is more convenient. Although this method is more convenient, it seems to me that he would be more difficult for beginners, in this I will not describe it in detail. If someone wants to become more familiar with this method, you can see how it is implemented in the "Hero of Sparta", just compare the files "HeroOfSparta.smali" with the original version and the version optimized for HVGA / QVGA
 
Last edited:

BPaul

Inactive Recognized Developer
May 9, 2011
2,355
8,117
31
Astana
empireb.ml
3. How to disable cache
This step is even simpler, the file "GameInstaller.smali" find function "isRequiredFile"
HTML:
.method private isRequiredFile(Ljava/lang/String;J)Z
    .locals 5
    .parameter "fileName"
    .parameter "size"

    .prologue
    const/4 v4, 0x1

    .line 410
    new-instance v2, Ljava/lang/StringBuilder;

    invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V

    sget-object v3, Lcom/gameloft/android/GAND/GloftMCHP/GameInstaller;->DATA_PATH:Ljava/lang/String;

    invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v2

    invoke-virtual {v2, p1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v2

    invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v1

    .line 411
    .local v1, path:Ljava/lang/String;
    new-instance v0, Ljava/io/File;

    invoke-direct {v0, v1}, Ljava/io/File;-><init>(Ljava/lang/String;)V

    .line 412
    .local v0, file:Ljava/io/File;
    invoke-direct {p0, p1}, Lcom/gameloft/android/GAND/GloftMCHP/GameInstaller;->replaceOconf(Ljava/lang/String;)Z

    move-result v2

    if-eqz v2, :cond_0

    const/4 v2, 0x0

    .line 415
    :goto_0
    return v2

    :cond_0
    invoke-virtual {v0}, Ljava/io/File;->exists()Z

    move-result v2

    if-eqz v2, :cond_1

    invoke-virtual {v0}, Ljava/io/File;->length()J

    move-result-wide v2

    cmp-long v2, v2, p2

    if-eqz v2, :cond_2

    :cond_1
    const/4 v2, 0x0

    goto :goto_0

    :cond_2
    const/4 v2, 0x0

    goto :goto_0
.end method
In it we are interested in a fragment
HTML:
invoke-virtual {v0}, Ljava/io/File;->exists()Z

move-result v2

if-eqz v2, :cond_1

invoke-virtual {v0}, Ljava/io/File;->length()J

move-result-wide v2

cmp-long v2, v2, p2

if-eqz v2, :cond_2

:cond_1
const/4 v2, 0x0
In this passage there is a check whether a file exists in the cache and if so, the same as its size (or checksum) with the reference? We just cut a check for file existence, but comparing the size of a reference to itself:)
The result should so
HTML:
.method private isRequiredFile(Ljava/lang/String;J)Z
    .locals 5
    .parameter "fileName"
    .parameter "size"

    .prologue
    const/4 v4, 0x1

    .line 410
    new-instance v2, Ljava/lang/StringBuilder;

    invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V

    sget-object v3, Lcom/gameloft/android/GAND/GloftMCHP/GameInstaller;->DATA_PATH:Ljava/lang/String;

    invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v2

    invoke-virtual {v2, p1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v2

    invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v1

    .line 411
    .local v1, path:Ljava/lang/String;
    new-instance v0, Ljava/io/File;

    invoke-direct {v0, v1}, Ljava/io/File;-><init>(Ljava/lang/String;)V

    .line 412
    .local v0, file:Ljava/io/File;
    invoke-direct {p0, p1}, Lcom/gameloft/android/GAND/GloftMCHP/GameInstaller;->replaceOconf(Ljava/lang/String;)Z

    move-result v2

    if-eqz v2, :cond_0

    const/4 v2, 0x0

    .line 415
    :goto_0
    return v2

    :cond_0
    
    cmp-long v2, p2, p2

    if-eqz v2, :cond_2

    const/4 v2, 0x0

    goto :goto_0

    :cond_2
    const/4 v2, 0x0

    goto :goto_0
.end method
HTML:
In some games, mostly to the new function "isRequiredFile" does not, then focus on the snippets "invoke-virtual {v0}, Ljava/io/File;->exists()Z", " invoke-virtual {v0}, Ljava/io/File;->length()J", if they go together and after we check if"cmp-...", then 99% of it is checking the cache, we proceed with it is similar to that described above.

4. Assigning a hardware button on any action
 
Last edited:

BPaul

Inactive Recognized Developer
May 9, 2011
2,355
8,117
31
Astana
empireb.ml
Useful
What if the game uses the wrong cache or does not start?
Sometimes such a situation, when the phone is not officially supported game, but the reasons for this game it will not start - no. And it starts, but textures are displayed incorrectly or not displayed. The problem is that the game does not know your phone and any unknown phone thinks PowerVR. Check if this is, quite simply, only need-only file "Build.prop", change the manufacturer and model of your phone, such as "HTC Desire" and if the game is run properly, then you have a similar situation. To solve this problem, we need to make an unknown phone was considered "Snapdragon".
Below is written, to a greater extent, belongs to the Games Gameloft.
Uncompressed AIC file we need to find 2 files "gi_settings.xml" and "data.txt", they usually are in the "res\raw".
Click the "gi_settings.xml" in a text editor, you should see something such content.
HTML:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<settings>

    <carriers>
        <carrier name="default">
            <wifi_only>1</wifi_only>
        </carrier>
        <carrier name="sprint">
            <wifi_only>0</wifi_only>
        </carrier>
    </carriers>
    
    <devices>
        <device>
            <manufacturer name="default">
                <pvrt_textures>1</pvrt_textures>
            </manufacturer>
        </device>

        <device>
            <manufacturer name="Samsung">
                <pvrt_textures>1</pvrt_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="SAMSUNG">
                <pvrt_textures>1</pvrt_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="samsung">
                <pvrt_textures>1</pvrt_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="motorola">
                <pvrt_textures>1</pvrt_textures>
            </manufacturer>
        </device>
        <device>
            <manufacturer name="samsung">
                <model name="modelxxx">
                    <atc_textures>1</atc_textures> <!-- sample to override manufacturer value for an specific device -->
                </model>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="htc">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="HTC">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="Htc">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        <device>
            <manufacturer name="Sharp">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="SHARP">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="sharp">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="Sony Ericsson">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="acer">
                <dxt_textures>1</dxt_textures>
            </manufacturer>
        </device>

        <device>
            <manufacturer name="sony">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="LGE">
                    <dxt_textures>1</dxt_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="lge">
                <model name="LG-SU660">
                    <dxt_textures>1</dxt_textures>
                </model>
            </manufacturer>
        </device>
    </devices>
    
</settings>
This file is given for each phone model, a cache (texture compression format) to use. Tag "<pvrt_textures> 1 </pvrt_textures> " indicates a texture format for "PoverVR", tag "<atc_textures> 1 </atc_textures> " at the texture format for "Snapdragon", and "<dxt_textures> 1 </dxt_textures> " on the texture format for "Tegra".
As we expected, the unknown device is "PoverVR".
HTML:
<manufacturer name="default">
    <pvrt_textures>1</pvrt_textures>
</manufacturer>
And LG is a device "Tegra"
HTML:
<manufacturer name="LGE">
    <dxt_textures>1</dxt_textures>
</manufacturer>
It is now clear for the game to start to consider your device "Snapdragon", to replace all the tags "<pvrt_textures> 1 </pvrt_textures> " and "<dxt_textures> 1 </dxt_textures> " on "<atc_textures> 1 </atc_textures > "make it through the" Edit / Change your text editor.
As a result, you should have
HTML:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<settings>

    <carriers>
        <carrier name="default">
            <wifi_only>1</wifi_only>
        </carrier>
        <carrier name="sprint">
            <wifi_only>0</wifi_only>
        </carrier>
    </carriers>
    
    <devices>
        <device>
            <manufacturer name="default">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>

        <device>
            <manufacturer name="Samsung">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="SAMSUNG">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="samsung">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="motorola">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        <device>
            <manufacturer name="samsung">
                <model name="modelxxx">
                    <atc_textures>1</atc_textures> <!-- sample to override manufacturer value for an specific device -->
                </model>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="htc">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="HTC">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="Htc">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        <device>
            <manufacturer name="Sharp">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="SHARP">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="sharp">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="Sony Ericsson">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="acer">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>

        <device>
            <manufacturer name="sony">
                <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="LGE">
                    <atc_textures>1</atc_textures>
            </manufacturer>
        </device>
        
        <device>
            <manufacturer name="lge">
                <model name="LG-SU660">
                    <atc_textures>1</atc_textures>
                </model>
            </manufacturer>
        </device>
    </devices>

</settings>
To be continued
 
Last edited:

BPaul

Inactive Recognized Developer
May 9, 2011
2,355
8,117
31
Astana
empireb.ml
Continued

In principle this is sufficient, but you can still, just in case, correct and "data.txt".
HTML:
PVRT:http://dl.gameloft.com/hdplus/android/DH2/i9000/ML/1.0.4/DH2_FINAL_PVRTC_104.zip
ATC:http://dl.gameloft.com/hdplus/android/DH2/HTC_EVO/ML/1.0.4/DH2_FINAL_ATC_104.zip
DXT:http://dl.gameloft.com/hdplus/android/DH2/LG_STAR/ML/1.0.4/DH2_FINAL_DXT_104.zip
It specifies which cache to use and where it is, for each type of accelerator. Address of 2 nd line, we copy in the 1 st and 3rd.
HTML:
PVRT:http://dl.gameloft.com/hdplus/android/DH2/HTC_EVO/ML/1.0.4/DH2_FINAL_ATC_104.zip
ATC:http://dl.gameloft.com/hdplus/android/DH2/HTC_EVO/ML/1.0.4/DH2_FINAL_ATC_104.zip
DXT:http://dl.gameloft.com/hdplus/android/DH2/HTC_EVO/ML/1.0.4/DH2_FINAL_ATC_104.zip
Thus, we point out the game, so it is not dependent on the type of accelerator used cash for "Snapdragon".
After that, the game should work correctly. By the way I always puzzling why the spread 10 times the cache under the "Snapdragon", with the headings "Cash for Desire ","Cash for Desire z ","Cash for Desire HD " if they are the same? Moreover, in games there are usually only 3 types of caches, for different video accelerators. This will make sure you can look a file "data.txt".

If the game does not start
Sometimes more so that the game does not start, but the objective reasons for this. Moreover, if the correct model of the device in "build.prop" game starts. This means that somewhere in the game code is a check Model/phone manufacturer, which resulted in the game just closes. It is clear that to solve this problem you need to make the game think she gets the right devices. For example, in "HTC Desire", if it is of course supported by the game. With the help of search through all the "*. smali" file and find those which meet the code "Landroid/os/Build;>MANUFACTURER:Ljava/lang/String" or "Landroid/os/Build;>MODEL:Ljava/lang/String". Thus we find the definition of the model code/ phone manufacturer.
HTML:
sget-object v0, Landroid/os/Build;->MANUFACTURER:Ljava/lang/String;

sget-object v1, Landroid/os/Build;->MODEL:Ljava/lang/String;
We need to be replaced by
HTML:
const-string v0, "HTC"

const-string v1, "HTC Desire"
(variables v0, v1-listed for an example, in your case, they may be different)
And so with all the files found.
In addition to the model/phone manufacturer in the same way in the game can also check the firmware version, or an android, and if it interferes with the launch of the game, these inspections can proceed similarly.

Analysis software package
Analyze JAVA-byte code files "*. smali", occupation rather complicated and a little sweet. But there is a way we can decompile apk-file and get the source code of JAVA. While these sources and are not suitable for the compilation, but a study of the program make it easy at times. For this we need 2 programs dex2jar and jd-gui, they should be extracted to arbitrary folders. Next, using the archiver with guinea apk-file to extract and copy the folder with the "dex2jar" file "classes.dex". From the command prompt run the command "dex2jar.bat classes.dex", as a result of the last in the folder "dex2jar" get file "classes.dex.dex2jar.jar". Now run the program "jd-gui" in her opening, obtained earlier, the file "classes.dex.dex2jar.jar".
The result is a readable code JAVA.
jd_gui.png
 
Last edited:

Top Liked Posts

  • There are no posts matching your filters.
  • 17
    Recently, a lot of me in a personal message arrives with a question in about optimizing games for screens HVGA, QVGA. Since this question is relevant to many, I decided to write a short statement. Just want to warn you that every game has its own nuances and using the information described here will likely have to adjust it to suit your particular case, moreover, this statement is mostly true to the games from Gameloft. It is also very desirable to have programming skills, even if it is not under an android. In any case, I hope this statement will be helpful and will help to understand the approximate algorithm of actions. Android platform I started relatively recently, perhaps doing something not quite right / best, to it - the guru of the forum, please do not throw rotten tomatoes, and indicate an error, suggest a better option.

    Let's start ...

    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.
    HTML:
    .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.
    HTML:
    .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".
    HTML:
    .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
    HTML:
    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
    HTML:
    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)
    Note
    In other games instead of code, maybe something like this
    HTML:
    invoke-virtual {v0}, Landroid/view/Display;->getWidth()I
    
    move-result v3
    
    invoke-virtual {v0}, Landroid/view/Display;->getHeight()I
    
    move-result v4
    Anyway replace it at:
    HTML:
    const/16 v3, 0x320
    
    const/16 v4, 0x1E0
    Or variable names can not v3, v4 and v1, v2. Or nothing at all like it to be, and then change nothing.
    Or if problems arise, you can just in case, go looking for all "*. smali" files and replace all function calls "Landroid / view / Display; -> getWidth () I" and "Landroid / view / Display; -> getHeight () I ", suffer from it will not.
    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
    Welcome_to_IDA.png

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

    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 ".
    Load_a_new_file.png

    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 :D
    The fact that reverse engineering is completed, will show a message "The initial autoanalysis has been finished." in the lower box "Output window".
    Dism1.png

    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".
    Dism2.png

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

    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".
    VP1.png

    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.
    VP2.png

    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.
    UE1.png

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

    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".
    UE2.png

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

    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.
    3
    I found tutorial optimization games HD for QVGA/HVGA.

    Code:
    http://4pda.ru/forum/index.php?showtopic=238460

    I'm waiting for yours work. :)
    3
    P.S. Russian language is very complicated so I'm still translating! So what are waiting for will soon have everything!
    2
    I tried this tutorial with Galaxy on Fire 2, and I can't find OnDraw on any of the .smali files.

    Galaxy On Fire 2 is for QVGA !!!
    by ChojaK from www.smart4u.org !!!
    2
    there in Russian will be the time I'll translate