libgdx particleEffect rotation - android

I draw fire on my android device with libgdx:
ParticleEffect effect;
ParticleEffectPool fireEffectPool;
Array<PooledEffect> effects = new Array<PooledEffect>();
#Override
public void create()
{
...
effect = new ParticleEffect();
effect.load(Gdx.files.internal("particles/fire01.p"), Gdx.files.internal("image"));
effect.setFlip(true, false);
fireEffectPool = new ParticleEffectPool(effect, 1000, 3000);
PooledEffect myEffect = fireEffectPool.obtain();
myEffect.setPosition(200, 400);
effects.add(myEffect);
...
}
Can I rotate, set speed or scale my effect programmatically?

I found the solution to the particle effect rotation problem by using this code as base
http://badlogicgames.com/forum/viewtopic.php?f=11&t=7060#p32607
And adding a small change to conserve the amplitude of the effect. Hope it helps.
public void rotateBy(float amountInDegrees) {
Array<ParticleEmitter> emitters = particleEffect.getEmitters();
for (int i = 0; i < emitters.size; i++) {
ScaledNumericValue val = emitters.get(i).getAngle();
float amplitude = (val.getHighMax() - val.getHighMin()) / 2f;
float h1 = amountInDegrees + amplitude;
float h2 = amountInDegrees - amplitude;
val.setHigh(h1, h2);
val.setLow(amountInDegrees);
}
}
}

Yes. Check out the ParticleEmitterTest: https://github.com/libgdx/libgdx/blob/master/tests/gdx-tests/src/com/badlogic/gdx/tests/ParticleEmitterTest.java
You just need to obtain a ParticleEmitter:
emitter = effect.getEmitters().first();
emitter.getScale().setHigh(5, 20);

Related

How do you make shading work between several 3D objects using rajawali?

I made a 3D environment with a few 3D objects using rajawali. I set up a directionnal light, everything displays, I added diffuse material to every object.
But I can not have the shadow of one object on another.
The objects have their own shadows on themselves depending on how they are oriented within the directionnal light but they doesnt seem to have shadows of other objects. I also tried with a spotlight but it didnt work.
What can I do ? Is there a feature to enable or something ?
Here is my code :
public class BasicRenderer extends Renderer {
private Sphere mEarthSphere;
private DirectionalLight mDirectionalLight;
private SpotLight mSpotLight;
private Object3D[][][] mCubes;
private Object3D mRootCube;
public BasicRenderer(Context context) {
super(context);
setFrameRate(60);
}
#Override
protected void initScene() {
getCurrentScene().setBackgroundColor(0, 0.5f, 1.0f, 1.0f);
getCurrentScene().setFog(new FogMaterialPlugin.FogParams(FogMaterialPlugin.FogType.LINEAR, 0x999999, 50, 100));
mSpotLight = new SpotLight();
mSpotLight.setPower(20);
mSpotLight.enableLookAt();
mSpotLight.setPosition(new Vector3(2, 1, 0));
mSpotLight.setLookAt(0,0,0);
//getCurrentScene().addLight(mSpotLight);
mDirectionalLight = new DirectionalLight(-1f, -2f, -1.0f);
mDirectionalLight.setColor(1.0f, 1.0f, 1.0f);
mDirectionalLight.setPower(1.5f);
getCurrentScene().addLight(mDirectionalLight);
SpecularMethod.Phong phongMethod = new SpecularMethod.Phong(0xeeeeee, 200);
Material material = new Material();
material.enableLighting(true);
material.setDiffuseMethod(new DiffuseMethod.Lambert());
//material.setSpecularMethod(phongMethod);
Texture earthTexture = new Texture("Earth", R.drawable.earthtruecolor_nasa_big);
NormalMapTexture earthNormal = new NormalMapTexture("earthNormal", R.drawable.earthtruecolor_nasa_big_n);
earthTexture.setInfluence(.5f);
try{
material.addTexture(earthTexture);
material.addTexture(earthNormal);
} catch (ATexture.TextureException error){
Log.d("BasicRenderer" + ".initScene", error.toString());
}
material.setColorInfluence(0);
mEarthSphere = new Sphere(1, 24, 24);
mEarthSphere.setMaterial(material);
getCurrentScene().addChild(mEarthSphere);
getCurrentCamera().setZ(4.2f);
mCubes = new Object3D[30][30][2];
Material cubeMaterial = new Material();
cubeMaterial.enableLighting(true);
cubeMaterial.setDiffuseMethod(new DiffuseMethod.Lambert(1));
//cubeMaterial.setSpecularMethod(phongMethod);
cubeMaterial.enableTime(true);
cubeMaterial.setColorInfluence(0);
Texture cubeTexture = new Texture("Stone", R.drawable.stone);
try{
cubeMaterial.addTexture(cubeTexture);
} catch (ATexture.TextureException error){
Log.d("BasicRenderer" + ".initScene", error.toString());
}
cubeMaterial.addPlugin(new DepthMaterialPlugin());
mRootCube = new Cube(1);
mRootCube.setMaterial(cubeMaterial);
mRootCube.setY(-1f);
// -- similar objects with the same material, optimize
mRootCube.setRenderChildrenAsBatch(true);
getCurrentScene().addChild(mRootCube);
mCubes[0][0][0] = mRootCube;
for(int z = 0; z < 2; z++) {
for(int y = 0; y < 5; y++) {
for (int x = 0; x < 30; x++) {
Object3D cube = mRootCube.clone(true);
cube.setY(-5 + y);
cube.setX(-15 + x);
cube.setZ(z);
mRootCube.addChild(cube);
mCubes[x][y][z] = cube;
}
}
}
Object3D cube = mRootCube.clone(true);
cube.setY(0);
cube.setX(-15 + 10);
cube.setZ(1);
mRootCube.addChild(cube);
mCubes[5][10][1] = cube;
getCurrentScene().addChild(mCubes[5][10][1]);
// -- create a chase camera
// the first parameter is the camera offset
// the second parameter is the interpolation factor
ChaseCamera chaseCamera = new ChaseCamera(new Vector3(0, 3, 16), mEarthSphere);
// -- tell the camera which object to chase
// -- set the far plane to 1000 so that we actually see the sky sphere
chaseCamera.setFarPlane(1000);
getCurrentScene().replaceAndSwitchCamera(chaseCamera, 0); //<--Also the only change!!!
}
#Override
public void onRender(final long elapsedTime, final double deltaTime) {
super.onRender(elapsedTime, deltaTime);
mEarthSphere.rotate(Vector3.Axis.Y, 1.0);
}
}
As you can see on the next picture, there is no shadow on the ground next to the cube on the left, but I think there should be.
https://i.imgur.com/qtl6mZf.jpg

invalidate not redrawing view on api 25

I have a custom view that extends LinearLayout.
The view looks like progress bar with a little icon that moves on every click.
the updating method is :
public void setPointerOffset(int mPointerOffset) {
this.mPointerOffset = mPointerOffset;
updateSlider();
invalidate();
requestLayout();
}
private void updateSlider() {
PercentFrameLayout.LayoutParams params = (PercentFrameLayout.LayoutParams) mPointer.getLayoutParams();
PercentLayoutHelper.PercentLayoutInfo info = params.getPercentLayoutInfo();
if (mPointerOffset < MIN_OFFSET)
mPointerOffset = MIN_OFFSET;
if (mPointerOffset > MAX_OFFSET)
mPointerOffset = MAX_OFFSET;
float percent = mPointerOffset * 0.01f;
info.startMarginPercent = percent;
}
This method is fired up from onClickListener.
This is working great in low api like 17, but on the lest on (25) it doesn't working at all.
setting layout params to "mPointer" semms to fix it.
private void updateSlider() {
PercentFrameLayout.LayoutParams params = (PercentFrameLayout.LayoutParams) mPointer.getLayoutParams();
PercentLayoutHelper.PercentLayoutInfo info = params.getPercentLayoutInfo();
if (mPointerOffset < MIN_OFFSET)
mPointerOffset = MIN_OFFSET;
if (mPointerOffset > MAX_OFFSET)
mPointerOffset = MAX_OFFSET;
float percent = mPointerOffset * 0.01f;
info.startMarginPercent = percent;
mPointer.setLayoutParams(params);
}

Change FOV in Unity VR app

I am trying ot change FOV value ofr a VR camera in Unity. In editor works just fine but when i put the app on phone, thecamera has the defaul FOV value. Can somebody please tell me how can i effectively change the FOV value on phone?
Thanks
You can do it through code. Here's a script that will let you tap to adjust the FOV in realtime.
using UnityEngine;
using System.Collections;
using UnityEngine.VR; // you always need this to use special VR functions
public class VRUtility : MonoBehaviour {
public GameObject camGroup;
public Camera leftCam;
public Camera rightCam;
public float fov;
private float fovMin = 40;
private float fovMax = 100;
private float camGroupX = 0;
private float camGroupXMin = 0;
private float camGroupXMax = 100;
private float camGroupXStep = 20;
// Use this for initialization
public void Start () {
// set render quality to 50%, sacrificing speed for visual quality
// this is pretty important on laptops, where the framerate is often quite low
// 50% quality actually isn't that bad
VRSettings.renderScale = 3.0f;
OVRTouchpad.Create();
OVRTouchpad.TouchHandler += HandleTouchHandler;
leftCam.fieldOfView = fov;
rightCam.fieldOfView = fov;
}
// Update is called once per frame
void Update () {
if ( Input.GetKeyDown(KeyCode.R) ) {
InputTracking.Recenter(); // recenter "North" for VR, so that you don't have to twist around randomlys
}
// dynamically adjust VR visual quality in-game
if ( Input.GetKeyDown(KeyCode.RightBracket) ) { // increase visual quality
VRSettings.renderScale = Mathf.Clamp01( VRSettings.renderScale + 0.1f);
}
if ( Input.GetKeyDown(KeyCode.LeftBracket) ) { // decrease visual quality
VRSettings.renderScale = Mathf.Clamp01( VRSettings.renderScale - 0.1f);
}
}
private void HandleTouchHandler(object sender, System.EventArgs e){
var touchArgs = (OVRTouchpad.TouchArgs)e;
if (touchArgs.TouchType == OVRTouchpad.TouchEvent.SingleTap) {
fov += 10;
if (fov > fovMax) {
fov = fovMin;
}
leftCam.fieldOfView = fov;
rightCam.fieldOfView = fov;
}
if (touchArgs.TouchType == OVRTouchpad.TouchEvent.Left || touchArgs.TouchType == OVRTouchpad.TouchEvent.Right){
camGroupX += camGroupXStep;
if (camGroupX > camGroupXMax){
camGroupX = camGroupXMin;
}
camGroup.transform.position = new Vector3(camGroupX, 0, 0);
}
}
}
I'm also moving a camera between locations, but just ignore that.

Can't get colored image on Android usin objloader library

I have made a sketch in processing using saitoobjloader and controlP5 librarys, and it works just fine, and after that i have exported as an android app to import it in eclipse. I have runned it then on my phone, from eclipse, and it works, except that, everything is black and white.I have tried model.disableMaterial(), model.disableTexture() and it does not work, I have seted for android 2.3.3, 4.2.2, 4.4 and it also don't work...stil black and white. I have tried primitive debug by disabeling everything i can one by one: the animation, the boject loaded, screen orientation and stil black and white. Idon't have any permisions aded, and the only change i have made is for screen orientation in manifes aplication: Debuggable --> null, Screen orientation --> unspecified, Config changes --> orientation.
Below you can see my code from eclipse:
package processing.test.my_cnc_obj_with_gui_mooving_animation;
import processing.core.*;
import android.content.res.Configuration;
import saito.objloader.*;
import controlP5.*;
public class My_cnc_obj_with_GUI_mooving_animation extends PApplet {
OBJModel model;
ControlP5 sb;
float rotX;
float rotY;
float zoom = 1;
float translateX;
float translateY;
float k;
int i;
float initlength = 250;
int initlengthX = 150;
int initlengthY = 150;
int initlengthZ = 80;
float moveIndex;
float AXA_X;
float AXA_Y;
float AXA_Z;
public void setup() {
model = new OBJModel(this, "CNC colorat pentru processing.obj");
model.scale(400);
model.translateToCenter();
//model.disableTexture();
model.disableMaterial();
//model.disableDebug();
controlereGUI();
noStroke();
}
public void draw() {
background(50, 34, 32);
lights();
// fill(255,0,255);
pushMatrix();
translate(width/2 - 50, height/2, 0);
rotateX(rotY);
rotateY(rotX);
model.draw();
model.disableMaterial();
popMatrix();
animation();
}
public void mouseDragged()
{
rotX += (mouseX - pmouseX) * 0.01f;
rotY -= (mouseY - pmouseY) * 0.01f;
}
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
int orientation = newConfig.orientation;
model.disableMaterial();
//Something strange happened... bail out!
if(orientation == Configuration.ORIENTATION_UNDEFINED)
return;
orientation = Configuration.ORIENTATION_PORTRAIT;
if(orientation == Configuration.ORIENTATION_LANDSCAPE) {
//Landscape config
}
if(orientation == Configuration.ORIENTATION_PORTRAIT) {
//Portrait config
}
}
/*public void mouseWheel(MouseEvent e) {
translateX = translateX-e.getAmount()*(mouseX)/100;
translateY = translateY-e.getAmount()*(mouseY)/100;
zoom += e.getAmount() / 100;
model.scale(zoom);
}*/
public void controlereGUI() {
sb = new ControlP5(this);
sb.getTab("default")
//.activateTab("Assisted_controll")
//.activateEvent(true)
.setHeight(40)
.setLabel("Assisted controll")
.setId(3)
;
sb.getTab("Manual_controll")
//.activateTab("Manual_controll")
//.activateEvent(true)
.setHeight(40)
.setLabel("Manual controll")
.setId(1)
;
sb.addTab("Settings")
//.activateTab("Settings")
.setHeight(40)
.setWidth(60)
.setLabel("Settings")
.setId(2)
.setColorBackground(color(0, 160, 100))
//.activateEvent(true)
.setColorLabel(color(255))
.setColorActive(color(255, 128, 0))
;
sb.addSlider("AXA_X")
.setPosition(10, 70)
//.setWidth(300)
.setSize(300, 30)
.setRange(initlength, 0)
//.setValue(128)
.setSliderMode(Slider.FLEXIBLE)
;
sb.addSlider("AXA_Y")
.setPosition(10, 110)
//.setWidth(300)
.setSize(300, 30)
.setRange(initlengthY, -initlengthY)
//.setValue(128)
.setSliderMode(Slider.FLEXIBLE)
.setColorForeground(0xffFC0000)
.setColorBackground(color(150, 0, 0))
;
sb.addSlider("AXA_Z")
.setPosition(10, 150)
//.setWidth(300)
.setSize(300, 30)
.setRange(initlengthZ + 120, 70)
//.setValue(128)
.setSliderMode(Slider.FLEXIBLE)
.setColorForeground(0xff0BFC00)
.setColorBackground(color(100, 150, 0))
;
sb.addButton("Start_movement")
.setBroadcast(false)
.setValue(128)
.setPosition(120, height-160)
//.setImages(imgs)
.setSize(90, 50)
.setCaptionLabel("Start movement")
.setColorBackground(color(100, 150, 0))
//.setVisible(false)
.setBroadcast(true)
;
sb.addButton("Stop_movement")
.setValue(128)
.setPosition(120, height-100)
//.setImages(imgs)
.setSize(90, 50)
.setCaptionLabel("Stop movement")
.setColorBackground(color(150, 0, 0))
//.setVisible(false)
;
}
public void animation() {
for (int i = 0; i < model.getVertexCount () - 6090; i++) {
PVector orgv = model.getVertex(i);
PVector tmpv = new PVector();
tmpv.x = orgv.x;
tmpv.y = orgv.y;
tmpv.z = orgv.z + (k * AXA_Y);
model.setVertex(i, tmpv);
}
if ((AXA_Y != 0)) {
if (moveIndex < AXA_Y)
moveIndex ++;
else
if (moveIndex > AXA_Y)
moveIndex --;
else
k = 0;
k = 1;
} else {
moveIndex = AXA_Y;
k = 0;
}
}
public int sketchWidth() { return 800; }
public int sketchHeight() { return 700; }
public String sketchRenderer() { return P3D; }
}
I don'tknow why is stil black and white.
Thanks in advance.
Solved.
It seems that i must use a combination of use of material (not disable it) and after drawing the model to stop the lights. So, it should be like in the code above, with this modifications:
public void setup() {
model = new OBJModel(this, "CNC colorat pentru processing.obj");
model.scale(400);
model.translateToCenter();
controlereGUI();
noStroke();
}
public void draw() {
background(50, 34, 32);
lights();
// fill(255,0,255);
pushMatrix();
translate(width/2 - 50, height/2, 0);
rotateX(rotY);
rotateY(rotX);
model.draw();
popMatrix();
noLights();
animation();
}
However, it seems that the 3D model remains still black and white even if is coloured. The 3D model was modified with Blender v2.71 (imported as .wrl file and exported as .obj with .mtl file). The .wrl file has been initial colored and when it was imported in Blender everything was ok, the model was colored. It seems that processing can't get the material. The debug shows: Material 'Shape.1687' not defined, ..., Material 'Shape.001' not defined,
Material 'Shape' not defined
I don't know where the problem is: inside saitoobjloader or the .obj and .mtl files....
Solved the second problem too. The problem is in file's name "CNC colorat pentru processing".
It seems that saito's objloader parser does not read spaces caracter (" ") in files name, so when i am making a new obj file (in blender or any other), i should have save it with the name "CNC_colorat_pentru_processing", or any other name that does not contain space caracter.

libgdx pixel issues between desktop and android projects

UPDATE Looks like this is a problem because of the static notification bar on tablet because of the lack of hardware buttons. I just didn't think about that. Anyway, in the case of the TF101 it returns a resolution of 1280x752 so about 1.702 (80 : 47) ratio. If I use a suitable unit size, like 33.5 or 11.75 vertically I get the proper scaling and this seems to fix the problem of skewed pixels.
END UPDATE
I've been setting up a game using 16x16 units for my tiled maps. I am using the resolution 1280x800 on both my desktop and android projects, I'm testing this to get a sense of how it will look on my TF101 asus tablet. I currently use a camera with units of 20x12.5 (wxh) and notice no pixel scaling on my desktop project, but when I run the game on my android I get weird scaling, and a green horizontal line. I can also move about quarter cell further along the x-axis on the tablet, shown in the screen shots. The pixels on the android project don't seem uniform at all.
I set the verticalTiles amount to 12.5f, then calculate the horizontalTiles amount as
verticalTiles = 12.5f;
...
horizontalTiles = (float) width / (float) height * verticalTiles;
camera = new OrthographicCamera(horizontalTiles, verticalTiles);
I'm aiming for devices with different aspect ratios to simply see more or less of the map, but can't seem to get working correctly. Any help would be appreciated.
Android Capture - http://imageshack.us/f/7/dsvg.png/ - notice the highlights on the roof edges, they are not uniform at all.
Desktop Capture - http://imageshack.us/f/853/5itv.png/
Current MainGame class
package com.bitknight.bqex;
/* Bunch of imports */
public class MainGame implements ApplicationListener {
private OrthographicCamera camera;
private SpriteBatch spriteBatch;
private TiledMap map;
private OrthogonalTiledMapRenderer mapRenderer;
private Texture texture;
private Texture clothArmor;
private Sprite sprite;
private BitmapFont font;
private float horizontalTiles = 0;
private float verticalTiles = 12.5f;
private int hoverTileX = 0;
private int hoverTileY = 0;
private TiledMapTileLayer layer;
private Cell cell;
private TiledMapTile canMoveToTile;
private TiledMapTile cannotMoveToTile;
private AnimatedTiledMapTile animatedStopTile;
private AnimatedTiledMapTile animatedGoTile;
private Texture spriteSheet;
private TextureRegion region;
private Player player;
float h, w;
float ppuX, ppuY;
#Override
public void create() {
// Setup the animated tiles
Array<StaticTiledMapTile> tileArray;
// Start position on the sheet
int startX = 192;
int startY = 1568;
spriteSheet = new Texture(Gdx.files.internal("data/maps/tilesheet.png"));
spriteSheet.setFilter(TextureFilter.Nearest, TextureFilter.Nearest);
// We are trying to load two strips of 4 frames, 8 total
for( int i = 0; i < 2; ++i ) {
tileArray = new Array<StaticTiledMapTile>(4);
for( int j = 0; j < 4; ++j ) {
region = new TextureRegion(spriteSheet, startX, startY, 16, 16);
tileArray.add(new StaticTiledMapTile(region));
startX += 16;
}
if( i == 0 ) {
animatedStopTile = new AnimatedTiledMapTile(1/10f, tileArray);
} else {
animatedGoTile = new AnimatedTiledMapTile(1/10f, tileArray);
}
}
// Load the map
map = new TmxMapLoader().load("data/maps/base.tmx");
// Setup the two tiles that show movable and not movable sprites
canMoveToTile = map.getTileSets().getTileSet(0).getTile(1959);
canMoveToTile.setBlendMode(BlendMode.ALPHA);
cannotMoveToTile = map.getTileSets().getTileSet(0).getTile(1958);
cannotMoveToTile.setBlendMode(BlendMode.ALPHA);
// Manually create the layer used to show the cursor sprites
layer = new TiledMapTileLayer(100, 100, 16, 16);
layer.setName("display");
cell = new Cell();
cell.setTile(canMoveToTile);
layer.setOpacity(1f);
mapRenderer = new OrthogonalTiledMapRenderer(map, 1/16f);
spriteBatch = new SpriteBatch();
font = new BitmapFont(Gdx.files.internal("data/consolas.fnt"), false);
font.setScale(0.6f);
texture = new Texture(Gdx.files.internal("data/maps/tilesheet.png"));
texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
clothArmor = new Texture(Gdx.files.internal("data/img/native/clotharmor.png"));
region = new TextureRegion(clothArmor, 32, 256, 32, 32);
sprite = new Sprite(region);
sprite.setOrigin(0.5f, 0.5f);
sprite.setPosition(0f - 0.5f, 0f);
sprite.setSize(2, 2);
// Setup player and associated animations
Array<TextureRegion> regions = new Array<TextureRegion>();
player = new Player();
}
#Override
public void dispose() {
spriteBatch.dispose();
texture.dispose();
clothArmor.dispose();
spriteSheet.dispose();
}
#Override
public void render() {
player.update(Gdx.graphics.getDeltaTime());
camera.update();
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if( Gdx.input.isKeyPressed(Input.Keys.ESCAPE) ) {
Gdx.app.exit();
}
// Clear the last cell
layer.setCell(hoverTileX, hoverTileY, null);
// Convert screen coordinates to world coordinates
Vector3 worldCoordinates = new Vector3(Gdx.input.getX(0), Gdx.input.getY(0), 0);
camera.unproject(worldCoordinates);
hoverTileX = (int)(worldCoordinates.x);
hoverTileY = (int)(worldCoordinates.y);
TiledMapTileLayer layer = (TiledMapTileLayer)map.getLayers().get("collision");
if( Gdx.input.isTouched(0) ) {
//sprite.setPosition(hoverTileX - 0.5f, hoverTileY);
player.pos.x = hoverTileX - 0.5f;
player.pos.y = hoverTileY - 0.25f;
cell.setTile(animatedGoTile);
} else {
if (layer.getCell(hoverTileX, hoverTileY) != null) {
cell.setTile(cannotMoveToTile);
} else {
cell.setTile(canMoveToTile);
}
}
layer.setCell(hoverTileX, hoverTileY, cell);
mapRenderer.setView(camera);
mapRenderer.render();
mapRenderer.getSpriteBatch().begin();
mapRenderer.renderTileLayer(layer);
mapRenderer.getSpriteBatch().end();
spriteBatch.setProjectionMatrix(camera.combined);
spriteBatch.begin();
player.render(spriteBatch);
spriteBatch.end();
}
#Override
public void resize(int width, int height) {
horizontalTiles = (float) width / (float) height * verticalTiles;
camera = new OrthographicCamera(horizontalTiles, verticalTiles);
w = width;
h = height;
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}
Looks like this is a problem because of the static notification bar on tablet because of the lack of hardware buttons. I just didn't think about that. Anyway, in the case of the TF101 it returns a resolution of 1280x752 so about 1.702 (80 : 47) ratio. If I use a suitable unit size, like 33.5 or 11.75 vertically I get the proper scaling and this seems to fix the problem of skewed pixels.
Also, while this is good for the TF101 tablet in my case it's not really a great solution. Here is a Gemserk series that talks about a nice solution.
http://blog.gemserk.com/2013/01/22/our-solution-to-handle-multiple-screen-sizes-in-android-part-one/

Categories

Resources