Problem with OpenGL ES application - Android Software Development

Hi there,
I am currently trying to develop a game for android in OpenGL ES....and I am testing it on my Nexus One. But I have run into some problems with performance.
I currently have a very basic scene - background made of 25 tiles(256x256 texture each), and then a number of textured cubes(128x128 texture for each side of a cube ). However,when I try to display approx. more than 10 cubes, the performance becomes so sluggish that I can't even rotate the scene smoothly. I can't imagine how can I add more objects(player,enemies, all that kind of stuff) when it runs so slowly with 35 objects in total. I mean - games like Raging Thunder 2 probably display hundreds of objects at once(plus they do lots of computations behind the scenes) and they run super-smooth on my nexus one. What am I doing wrong? Could somebody help me please????

Are you rendering all 25 tiles at once? Try rendering your cubs without the the background

It is not really a fault of either cubes or background - if I try to disable background,but leave ~30 cubes, it's slow. But if I don't display any cubes,but 50 tiles for the background, it is also slow.
I must be doing something else wrong, I don't know -don't initialize opengl properly, have some antialiasing turned on, I seriously have no idea - I am asking if you know what may be a _typical_ reason for sluggish performance in opengl,as I am new to opengl es(used opengl earlier though) and I may have easily overlooked something.
That's how it looks like:
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Do you think that there is seriously too much stuff on the screen?

How many bit textures are you using?

jug6ernaut said:
How many bit textures are you using?
Click to expand...
Click to collapse
Bit textures? I only use two textures:
Nothing else. The multi coloured cube in the middle is just a gradient cube.

While i am not anywhere close to a gl Pro(im sure u actually know more then be based on ur program), but your background is made up of 25 tiles of your texture which is 107kbs, so with just the background only you are trying to render 25x107kbs = 2675kbs of data every frame. I would have to guess that this is alot, tho as i said i am not a pro at all. For more information i would recommend going to the irc #opengl channel on the irc.freenode.net server. They should be able to help you out .

jug6ernaut said:
While i am not anywhere close to a gl Pro(im sure u actually know more then be based on ur program), but your background is made up of 25 tiles of your texture which is 107kbs, so with just the background only you are trying to render 25x107kbs = 2675kbs of data every frame. I would have to guess that this is alot, tho as i said i am not a pro at all. For more information i would recommend going to the irc #opengl channel on the irc.freenode.net server. They should be able to help you out .
Click to expand...
Click to collapse
I changed the resolution of the texture for tiles to 64x64(so it's 6kb now) and it isn't running any better....I guess it doesn't have anything to do with textures, I guess there is some instruction that consumes lots of computing power,and it gets executed with every object,so the more I have them,the slower it runs....
That's the main function for drawing the frame:
Code:
public void onDrawFrame(GL10 gl) {
gl.glDisable(GL10.GL_DITHER);
gl.glEnable(GL10.GL_SCISSOR_TEST);
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glScissor(0, 0, _width, _height);
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_FASTEST);
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
GLU.gluPerspective(gl, 50, (float)(800.0/480.0), 1, 100);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BITS);
GLU.gluLookAt(gl, _xValue, _yValue+5, -5, _xValue, _yValue-2, 0.0f, 0.0f,-1.0f,0.0f); //camera
//main cube with gradient
gl.glPushMatrix();
gl.glTranslatef(_xValue, _yValue, 0.0f);
mCube.draw(gl);
gl.glPopMatrix();
//lots of small textured cubes
for(int i=0;i<40;i++)
{
gl.glPushMatrix();
gl.glScalef(0.5f, 0.5f, 0.5f);
gl.glTranslatef(boxArrayX[i],boxArrayY[i],0);
tcube.draw(gl);
gl.glPopMatrix();
}
//draw the ground in tiles:
gl.glPushMatrix();
gl.glTranslatef(-16.0f, -16.0f, 1f);
for(int x=0;x<5;x++)
{
for(int y=0;y<5;y++)
{
gl.glPushMatrix();
gl.glScalef(4, 4, 0);
tsurface.draw(gl);
gl.glPopMatrix();
gl.glTranslatef(0,8,0);
}
gl.glTranslatef(8, 0, 0);
gl.glTranslatef(0, -40, 0);
}
gl.glPopMatrix();
}
That's a drawing routine for the textured boxes(I got it from a tutorial,so this is not mine):
Code:
public void draw(GL10 gl)
{
gl.glColorPointer(4, GL10.GL_FIXED, 0, colBuf);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glBindTexture(GL10.GL_TEXTURE_2D, texBuf.get(0));
gl.glVertexPointer(3, GL10.GL_FIXED, 0, vrtBuf_TU);
gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,crdUBuf);
gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_UNSIGNED_BYTE, ixdBuf);
gl.glVertexPointer(3, GL10.GL_FIXED, 0, vrtBuf_TD);
gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,crdDBuf);
gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_UNSIGNED_BYTE, ixdBuf);
gl.glBindTexture(GL10.GL_TEXTURE_2D, texBuf.get(1));
gl.glVertexPointer(3, GL10.GL_FIXED, 0, vrtBuf_BU);
gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,crdUBuf);
gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_UNSIGNED_BYTE, ixdBuf);
gl.glVertexPointer(3, GL10.GL_FIXED, 0, vrtBuf_BD);
gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,crdDBuf);
gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_UNSIGNED_BYTE, ixdBuf);
gl.glBindTexture(GL10.GL_TEXTURE_2D, texBuf.get(2));
gl.glVertexPointer(3, GL10.GL_FIXED, 0, vrtBuf_NU);
gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,crdUBuf);
gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_UNSIGNED_BYTE, ixdBuf);
gl.glVertexPointer(3, GL10.GL_FIXED, 0, vrtBuf_ND);
gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,crdDBuf);
gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_UNSIGNED_BYTE, ixdBuf);
gl.glBindTexture(GL10.GL_TEXTURE_2D, texBuf.get(3));
gl.glVertexPointer(3, GL10.GL_FIXED, 0, vrtBuf_SU);
gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,crdUBuf);
gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_UNSIGNED_BYTE, ixdBuf);
gl.glVertexPointer(3, GL10.GL_FIXED, 0, vrtBuf_SD);
gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,crdDBuf);
gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_UNSIGNED_BYTE, ixdBuf);
gl.glBindTexture(GL10.GL_TEXTURE_2D, texBuf.get(4));
gl.glVertexPointer(3, GL10.GL_FIXED, 0, vrtBuf_WU);
gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,crdUBuf);
gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_UNSIGNED_BYTE, ixdBuf);
gl.glVertexPointer(3, GL10.GL_FIXED, 0, vrtBuf_WD);
gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,crdDBuf);
gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_UNSIGNED_BYTE, ixdBuf);
gl.glBindTexture(GL10.GL_TEXTURE_2D, texBuf.get(5));
gl.glVertexPointer(3, GL10.GL_FIXED, 0, vrtBuf_OU);
gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,crdUBuf);
gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_UNSIGNED_BYTE, ixdBuf);
gl.glVertexPointer(3, GL10.GL_FIXED, 0, vrtBuf_OD);
gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,crdDBuf);
gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_UNSIGNED_BYTE, ixdBuf);
}
that's a routine for drawing the gradient box:
Code:
public void draw(GL10 gl)
{
gl.glDisable(GL10.GL_TEXTURE_2D);
gl.glPushMatrix();
gl.glScalef(0.5f, 0.5f, 0.5f);
gl.glVertexPointer(3, gl.GL_FIXED, 0, mVertexBuffer);
gl.glColorPointer(4, gl.GL_FIXED, 0, mColorBuffer);
gl.glDrawElements(gl.GL_TRIANGLES, 36, gl.GL_UNSIGNED_BYTE, mIndexBuffer);
gl.glPopMatrix();
}
routine for drawing the TSurface object(so ground tile) is just like drawing a top side of the textured box, I took the code from there.
So as far as I recon, this is all the code that executes in one frame. Do you see anything wrong with it?
EDIT: Yeah,and I checked now - changed both textures to 8x8.....still runs very choppy. So it's definitely not a problem with textures.

Im sorry i cant be of more help, one thing i can see is you have alot of gltranslatef's. AFAIK this function is not gfx accelerated. while i am guessing at this that might be adding to your slowdowns.

jug6ernaut said:
Im sorry i cant be of more help, one thing i can see is you have alot of gltranslatef's. AFAIK this function is not gfx accelerated. while i am guessing at this that might be adding to your slowdowns.
Click to expand...
Click to collapse
Ok, thanks anyhow ;-)
Could anybody else take a look at my code and help please?

Related

How to select programatically a today theme.

Hi. I am trying to select programatically a today theme. I ve found different examples and I am using this function:
Code:
BOOL LoadTheme(LPCTSTR pszThemeFile)
{
HKEY hKey;
LONG lRet;
TCHAR szCmdLine[MAX_PATH];
PROCESS_INFORMATION pi;
lRet = RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Today"), 0,
0, &hKey);
if(ERROR_SUCCESS == lRet) {
RegDeleteValue(hKey, _T("UseStartImage"));
_stprintf(szCmdLine,_T("/safe /noui /nouninstall /delete 0 \"%s\""),
pszThemeFile);
if(CreateProcess(_T("\\Windows\\wceload.exe"), szCmdLine, NULL, NULL,
FALSE, 0, NULL, NULL, NULL, &pi)) {
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
RegSetValueEx(hKey, _T("Skin"), 0, REG_SZ, (BYTE*)pszThemeFile,
sizeof(TCHAR) * (_tcsclen(pszThemeFile) + 1));
RegFlushKey(hKey);
}
RegCloseKey(hKey);
::SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0xF2, 0);
::SendMessage(HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0);
}
return (ERROR_SUCCESS == lRet);
}
Then I see how the background image changes, as color fonts but upper and lower bars, and scrooll bars doesnt change. Any idea? Thanks
Dani
Hi.
If a reset then It works. It seems the last postmessage dont do their job correctly. Any idea?
Ive noticed this just manually changing the theme, the keyboard icon background changes as expected, but the top and bottom bar do not, change it again and it works, although now im on a theme i dont want, so have to change again

Align 2 texts, 1 normal, 1 opposite

I make a android application with a button where in there a total of 4 texts and I want to align the first 2. One at the most left side of the bottom text and the other and the right side of the bottom text.
So from this:
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Code:
setText(item.title + " " + item.roomId + "\n" + item.teacher + " " + item.classes);
To this:
This is my class where I extend Button:
Code:
/**
* Custom view that represents a {@link ScheduleItem} instance, including its
* title and time span that it occupies. Usually organized automatically by
* {@link ScheduleItemsLayout} to match up against a {@link TimeRulerView}
* instance.
*/
public class ScheduleItemView extends Button {
private ScheduleItem mItem;
public ScheduleItemView(Context context, ScheduleItem item) {
super(context);
mItem = item;
setSingleLine(false);
setText(item.title + " " + item.roomId + "\n" + item.teacher + " "
+ item.classes);
// TODO: turn into color state list with layers?
int textColor = Color.WHITE;
int accentColor = item.accentColor;
LayerDrawable buttonDrawable = (LayerDrawable) context.getResources()
.getDrawable(R.drawable.btn_block);
buttonDrawable.getDrawable(0).setColorFilter(accentColor,
PorterDuff.Mode.SRC_ATOP);
buttonDrawable.getDrawable(1).setAlpha(item.containsStarred ? 255 : 0);
setTextColor(textColor);
setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources()
.getDimensionPixelSize(R.dimen.text_size_small));
setGravity(Gravity.CENTER | Gravity.BOTTOM);
setBackgroundDrawable(buttonDrawable);
}
public ScheduleItem getScheduleItem() {
return mItem;
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(),
MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
getMeasuredHeight(), MeasureSpec.EXACTLY));
// layout(getLeft(), getTop(), getRight(), getBottom());
setGravity(Gravity.CENTER);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getRight() - getLeft(), getBottom() - getTop());
}
}
What I've tried is instead of extending Button, extending RelativeLayout:
Code:
/**
* Custom view that represents a {@link ScheduleItem} instance, including its
* title and time span that it occupies. Usually organized automatically by
* {@link ScheduleItemsLayout} to match up against a {@link TimeRulerView}
* instance.
*/
public class ScheduleItemView extends RelativeLayout {
private ScheduleItem mItem;
public ScheduleItemView(Context context, ScheduleItem item) {
super(context);
mItem = item;
// TODO: turn into color state list with layers?
int textColor = Color.WHITE;
int accentColor = item.accentColor;
LayerDrawable buttonDrawable = (LayerDrawable) context.getResources()
.getDrawable(R.drawable.btn_block);
buttonDrawable.getDrawable(0).setColorFilter(accentColor,
PorterDuff.Mode.SRC_ATOP);
buttonDrawable.getDrawable(1).setAlpha(item.containsStarred ? 255 : 0);
// Three TextViews to hold the `title`, `roomId`
// and `teacher&room` independently
TextView tvTitle = new TextView(context);
TextView tvRoomId = new TextView(context);
TextView tvTeacherAndClasses = new TextView(context);
// Example ids
tvTitle.setId(100);
tvRoomId.setId(101);
tvTeacherAndClasses.setId(102);
tvTitle.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources()
.getDimensionPixelSize(R.dimen.text_size_small));
tvRoomId.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources()
.getDimensionPixelSize(R.dimen.text_size_small));
tvTeacherAndClasses.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(R.dimen.text_size_small));
tvTitle.setPadding(30, 20, 30, 0);
tvRoomId.setPadding(30, 20, 30, 0);
tvTeacherAndClasses.setPadding(30, 5, 30, 20);
tvTitle.setTextColor(textColor);
tvRoomId.setTextColor(textColor);
tvTeacherAndClasses.setTextColor(textColor);
// Set text
tvTitle.setText(item.title);
tvRoomId.setText(item.roomId);
tvTeacherAndClasses.setText(item.teacher + " " + item.classes);
// LayoutParms
RelativeLayout.LayoutParams paramsTitle = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
paramsTitle.addRule(RelativeLayout.ALIGN_LEFT,
tvTeacherAndClasses.getId());
RelativeLayout.LayoutParams paramsRoomId = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
paramsRoomId.addRule(RelativeLayout.ALIGN_RIGHT,
tvTeacherAndClasses.getId());
RelativeLayout.LayoutParams paramsTeacherAndClasses = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
paramsTeacherAndClasses.addRule(RelativeLayout.CENTER_HORIZONTAL);
paramsTeacherAndClasses.addRule(RelativeLayout.BELOW, tvTitle.getId());
// Add Views to this RelativeLayout
addView(tvTitle, paramsTitle);
addView(tvRoomId, paramsRoomId);
addView(tvTeacherAndClasses, paramsTeacherAndClasses);
// setGravity(Gravity.CENTER | Gravity.BOTTOM);
// Set the background as LayerDrawable
setBackgroundDrawable(buttonDrawable);
}
public ScheduleItem getScheduleItem() {
return mItem;
}
But then only the LayerDrawable is displaying, the text is not displaying. What I've done wrong? I hope that someone can help me with this, the guys on StackOverflow have point me in a good direction with the above code but it's still not working.
The source of the project can be downloaded here (which you can import in Eclipse):
http://we.tl/5PnmaZKXvL
RelativeLayout should be a good idea!
Have you debuged the app? What is the text of the TextViews? The text-size? Why do you set the ids for the TextViews?
Regards
EmptinessFiller said:
RelativeLayout should be a good idea!
Have you debuged the app? What is the text of the TextViews? The text-size? Why do you set the ids for the TextViews?
Regards
Click to expand...
Click to collapse
I've debugged the app, this is what I've tried:
Log the id's of tvTitle, tvRoomId, and tvTeacherAndClasses with getId() to see if the id's is set. (The id's are set in order to get the addRule working)
I've tried to comment these lines:
tvTitle.setId(100);
tvRoomId.setId(101);
tvTeacherAndClasses.setId(102);
And the following as well:
paramsTitle.addRule(RelativeLayout.ALIGN_LEFT, tvTeacherAndClasses.getId());
paramsRoomId.addRule(RelativeLayout.ALIGN_RIGHT, tvTeacherAndClasses.getId());
paramsTeacherAndClasses.addRule(RelativeLayout.BELOW, tvTitle.getId());
If the ids were the problem, the text should show, but the three textviews would overlap now. But I still see no text.
I've tried to give the TextView a color with tvTitle.setBackgroundColor(Color.GREEN); but I still see no text neither a color.
I've tried to comment out setBackgroundDrawable(buttonDrawable); to see if the text's show up. But then I see no text and no button.
I've also tried to use bringToFront() but neither the text is not showing
As last I've tried to use a concrete value for the TextSize with tvTitle.setTextSize(25) but the text is unfortunately not showing.
What could be the problems:
I use Android-ViewPagerIndicator and ViewPager this could be a problem. (Maybe with restoring the view state or multiple id's).
I've only switched a Button to RelativeLayout, I really don't see why problems being introduced in that transition. Does someone know what could be the problem?
Anyone? I've updated the post with a new download link.
You could call getPaint on the button instance and with measuretext you could get the size of the spaces to calculate the count of spaces for the specific size of the button
Just an idea, no idea how it will work in practice
Tapatalked...

[GUIDE] Text shine effect with gyroscope

I want to share some codes of a small effect that I implemented in my Android app called Arithmetic Puzzles. This is also a chance for me to listen to other people and make improvements. At the end of this post there is a link to the app so that you can see the code in action.
It is a text shining effect which reacts on device movements. It creates a feeling of glass surface of the text which shines and reflects light. Only outline of the text is shining.
Please note that the text in my case was very short - a number with 2 digits - which looks cool. If you will try a longer text then let me know how it looks
I grabbed some parts of my code from its context to put here so if there is something missing or irrelevant then just let me know.
So, here we go! The text shine is done extending a simple View:
Code:
public class EquationView extends View {
...
// the text to be drawn
private String mText;
private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint mTextShinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private int mShineColor;
private int mShineNoColor;
...
// constructors
public EquationView(Context context) {
super(context);
init(context);
}
public EquationView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public void initialize(Context context) {
// paints
setupPaint(mTextPaint, R.color.text_color, context); // text color (yellow for me)
setupPaint(mTextShinePaint, R.color.text_shine, context); // shine color (white for me)
mTextShinePaint.setDither(true);
mTextShinePaint.setStyle(Paint.Style.STROKE);
mTextShinePaint.setStrokeJoin(Paint.Join.ROUND);
mTextShinePaint.setStrokeMiter(10);
// colors
mTextShadowColor = context.getResources().getColor(R.color.text_shadow); (#AA454210 for me)
mShineColor = context.getResources().getColor(R.color.text_shine); (white for me)
mShineNoColor = context.getResources().getColor(android.R.color.transparent);
}
private void setupPaint(Paint paint, int colorId, Context context) {
paint.setColor(context.getResources().getColor(colorId));
paint.setTextAlign(Paint.Align.CENTER);
}
The initialization function is setting up the paint objects. Since I am going to use LinearGradient as a shader in my paint, I am setting the dither to true. I have already wrote about it in my previous guide. I am also setting the shine paint style to STROKE so that only the outline of the text is "shining".
The stroke parameters like join and miter are mostly set to make it look prettier.
I also set the text align to CENTER. This has effect during drawing of the text - when I tell the paint to draw a text at some (x, y) point, then x is considered as the center point of the whole text, thus text is centered horizontally on this origin.
Next, let's have a look at the onDraw() function:
Code:
...
private static final float TEXT_HEIGHT = 0.8f;
private static final float SHINE_THICKNESS = 0.015f;
private final float mShadowBlurRadius = 5.0f * getResources().getDisplayMetrics().density; // 5dp
private LinearGradient mShineGradient;
private int mTextShadowColor;
private float mShadowShiftX = 0.0f;
private float mShadowShiftY = 0.0f;
private Rect mBounds = new Rect();
private Rect mTextBounds = new Rect();
...
@Override
protected void onDraw(Canvas canvas) {
// step 1. collect information needed for drawing
canvas.getClipBounds(mBounds);
float centerX = mBounds.centerX();
float h = mBounds.height();
float textSize = h * TEXT_HEIGHT;
float textCenterY = mBounds.top + h * 0.5f;
// step 2. draw the shadows
mTextPaint.setShadowLayer(mShadowBlurRadius, mShadowShiftX, mShadowShiftY, mTextShadowColor);
drawText(mText, centerX, textCenterY, textSize, canvas, mTextPaint);
// step 3. draw the shine
if (mShineGradient != null) {
mTextShinePaint.setShader(mShineGradient);
mTextShinePaint.setStrokeWidth(TextSize * SHINE_THICKNESS);
drawText(mText, centerX, textCenterY, textSize, canvas, mTextShinePaint);
}
// step 4. draw the text
mTextPaint.clearShadowLayer();
drawText(mText, centerX, textCenterY, textSize, canvas, mTextPaint);
}
private void drawText(String text, float centerX, float centerY,
float size, Canvas canvas, Paint paint) {
paint.setTextSize(size);
paint.getTextBounds(text, 0, text.length(), mTextBounds);
canvas.drawText(text, centerX, centerY + mTextBounds.height() / 2.0f - mTextBounds.bottom, paint);
}
In step 1 I collect information for drawing like clip bounds (see previous guide for clip bounds), sizes and positions.
In step 2 I draw the shadows. I also want the shadows to move when device moves (on gyroscope events). I actually draw the text with shadows - the text will be overdrawn in next steps so only shadows will be left from this step. The offsets of the shadows - mShadowShiftX and mShadowShiftY - are updated based on gyroscope data.
In step 3 I draw the shine. I set the LinearGradient mShineGradient as the shader of the paint and then set the stroke width to SHINE_THICKNESS. Then I draw text with that shader. For more information on shaders see my previous guide. The mShineGradient is updated when new gyroscope data is received. We will come to this gradient creation later.
In step 4 I disable the shadows and draw the text again. It will overwrite only the text, not the shadows and not the shine, so I have only the outline shining.
A common drawText() function is used to draw the text. It first sets the text size (font size), then calculates the text bounds using getTextBounds(). This is needed to center the text around the origin point also in vertical direction since Paint.Align.CENTER is aligning only in horizontal direction.
TO BE CONTINUED in the thread, seems there is limit on post size...
CONTINUATION of the guide
Now lets see how is the mShineGradient created. This is done every time we got a new data from gyroscope:
Code:
...
// all the magic numbers here and in below function are results of experiments
private static final float MAX_ANGLE = (float)(Math.PI / 2.0);
private final float mShadowMaxShift = 5.0f * getResources().getDisplayMetrics().density; // 5dp
...
public void gyroChanged(float xAngle, float yAngle) {
// 1. shadows
float loweredMax = MAX_ANGLE / 4;
mShadowShiftX = (xAngle / loweredMax) * mShadowMaxShift;
mShadowShiftY = (yAngle / loweredMax) * mShadowMaxShift;
// put in [-mShadowMaxShift, mShadowMaxShift] range
if (mShadowShiftX > mShadowMaxShift) mShadowShiftX = mShadowMaxShift;
if (mShadowShiftX < -mShadowMaxShift) mShadowShiftX = -mShadowMaxShift;
if (mShadowShiftY > mShadowMaxShift) mShadowShiftY = mShadowMaxShift;
if (mShadowShiftY < -mShadowMaxShift) mShadowShiftY = -mShadowMaxShift;
// 2. shine
float angleX = xAngle / MAX_ANGLE;
float angleY = yAngle / MAX_ANGLE;
// put in [-1, 1] range
if (angleX > 1.0f) angleX = 1.0f;
if (angleX < -1.0f) angleX = -1.0f;
if (angleY > 1.0f) angleY = 1.0f;
if (angleY < -1.0f) angleY = -1.0f;
createShineGradient(angleX, angleY);
// redraw
invalidate();
}
The numbers and formulas are quite experimental, so you can play around to find the best numbers for your case. The meaning and usage of gyroChanged() function is explained in my previous guide.
The basic idea behind is to get the shine position based on device's rotation in X and Y direction. I convert the rotation into a range from -1 to 1 using some max angle that I defined. If both X and Y angles are -1 then the shine line is in the lower left corner of the text, if both are 1 then in upper right corner, otherwise somewhere in between.
Here is the createShineGradient() function:
Code:
...
private static final float SHINE_WIDTH = 0.07f;
private static final float SHINE_BLUR_WIDTH = 0.05f;
...
private void createShineGradient(float relativeX, float relativeY) {
if ((mBounds == null) || (mBounds.width() == 0) || (mBounds.height() == 0)) {
mShineGradient = null;
return;
}
// we want to scale the angles' range and take inner part of
// length 1 this will speed up the shine without sudden stops
final float SPEED_FACTOR = 4.0f;
relativeX *= SPEED_FACTOR;
relativeY *= SPEED_FACTOR;
float boxSize = mBounds.height() * 1.2f; // make the text box a bit bigger
float left = mBounds.centerX() - boxSize / 2.0f;
float top = mBounds.top;
// project the (relativeX, relativeY) point to the diagonal
float relative = (relativeX + relativeY) / 2.0f;
// shift by 0.5 to get a point from (0, 1) range
relative += 0.5f;
int[] colors = {mShineNoColor, mShineNoColor, mShineColor, mShineColor, mShineNoColor, mShineNoColor};
float[] positions = {0.0f, clamp(relative - SHINE_WIDTH - SHINE_BLUR_WIDTH),
clamp(relative - SHINE_WIDTH), clamp(relative + SHINE_WIDTH),
clamp(relative + SHINE_WIDTH + SHINE_BLUR_WIDTH), 1.0f};
mShineGradient = new LinearGradient(left, top + boxSize, left + boxSize, top,
colors, positions, Shader.TileMode.CLAMP);
}
private float clamp(float value) {
if (value < 0.0f) {
return 0;
}
if (value > 1.0f) {
return 1.0f;
}
return value;
}
Again, there are a lot of experimental stuff, you might want to play with it to come to a good solution. The LinearGradient shader is explained in my previous guide. However, here we use more colors so that we can have a white stripe in the middle with small color change gradients on borders. The picture below explains everything:
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
The idea is to project the relative angle of the device rotation in X and Y direction to a single point on the View's diagonal through which the shine will pass. This projection should result in continuous and more or less natural movement of the shine line during device rotation, the formula I used is a result of my tries and errors.
When a new gradient is created invalidate() is called and the view redraws itself.
Finally, to see this code in action, you can have a look at the app itself, its free:
Google Play:
Direct link:
Download
It would be nice to get some comments and suggestions, let me know your thoughts!

[Tutorial] Learn to create the game "Spin The Bottle" for Android

Hello,
I create that thread to present you a tutorial learning you to create the game "Spin The Bottle" for Android. It is also a good way to discover how to use Android Animations API.
What is better that creating some funny games to learn the basics of Android development ? Today, you’re going to discover more on the Android Animation API by creating the game “Spin The Bottle”.
Note that you can discover this tutorial in video on Youtube too :
Spin the bottle is a party game in which several players sit/stand/kneel in a circle. A bottle is placed on the floor in the center of the circle. A player spins the bottle, and must kiss the person to whom the bottle points when it stops spinning.
With our application, it is not necessary any more to have a real bottle, you will just need a smartphone. And it’s great because everyone has always a smartphone on him nowadays.
First step is to find two specific images : one for the floor which will be defined as background of the game and an other for the bottle which will be rotated during the game.
We have chosen to use these both images :
Floor image for the background
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Bottle image
Now, we need to define the layout of our game “Spin The Bottle”. We have a Relative Layout with the floor image as background and we add a bottle in the center of this layout :
Code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background">
<ImageView
android:id="@+id/bottle"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/beer_bottle"
android:layout_centerInParent="true" />
</RelativeLayout>
The next step is to write the Java code of the Main Activity. First, we get references for the views. Then, we install a click listener on the main layout of the Main Activity. Thus, the user will just have to touch the screen to spin the bottle and to start the game.
The core of the game is in the spinTheBottle() method. We are going to define a RotateAnimation from start angle to end angle centered on the center of the bottle. The end angle will be defined randomly to simulate really the game “Spin The Bottle”. We should store the last end angle value to restart the bottle in the same position for the next turn of the game.
The Code of the Main Activity will have the following form :
Code:
package com.ssaurel.spinthebottle;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.Toast;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
public static final Random RANDOM = new Random();
private View main;
private ImageView bottle;
private int lastAngle = -1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
main = findViewById(R.id.root);
bottle = (ImageView) findViewById(R.id.bottle);
main.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
spinTheBottle();
}
});
Toast.makeText(this, R.string.touch_to_spin, Toast.LENGTH_SHORT).show();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.action_spin :
spinTheBottle();
break;
case R.id.action_zero :
resetTheBottle();
break;
}
return super.onOptionsItemSelected(item);
}
private void spinTheBottle() {
int angle = RANDOM.nextInt(3600 - 360) + 360;
float pivotX = bottle.getWidth() / 2;
float pivotY = bottle.getHeight() / 2;
final Animation animRotate = new RotateAnimation(lastAngle == -1 ? 0 : lastAngle, angle, pivotX, pivotY);
lastAngle = angle;
animRotate.setDuration(2500);
animRotate.setFillAfter(true);
bottle.startAnimation(animRotate);
}
private void resetTheBottle() {
float pivotX = bottle.getWidth() / 2;
float pivotY = bottle.getHeight() / 2;
final Animation animRotate = new RotateAnimation(lastAngle == -1 ? 0 : lastAngle, 0, pivotX, pivotY);
lastAngle = -1;
animRotate.setDuration(2000);
animRotate.setFillAfter(true);
bottle.startAnimation(animRotate);
}
}
You can run the application and play your game :
To go further, you can download the game “Spin The Bottle” created in this tutorial on the Google Play Store :
https://play.google.com/store/apps/details?id=com.ssaurel.spinthebottle

[Tutorial][APP] PinP Shortcuts | How to Implement Picture in Picture Mode [API 26+]

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Picture in Picture Mode (PinP) introduced on Android 8 (API 26) for All Android devices.
Its most used functionality is to shoa w preview of some data like Video Players, Maps & etc.
But there is also an option to add Custom Action & with this, you can do whatever you want to do.
This is Tutorial is about How to Add PinP for an Activity & Implementing Custom Actions to Create Shortcuts of Other Apps & Open Them
Click to expand...
Click to collapse
# Let Start #​
What do you need to get started...
- Know How to Create Hello World Project
- Basic Info about Android Apps Files (.Java, .xml)/Components (Activity, Service)
Click to expand...
Click to collapse
What will you learn...
- Configure an Activity for PinP Mode
- Create PendingIntent
- Load Apps Info from PackageManager (AppName, AdaptiveIcons & etc)
- Load File Data in Lines
Click to expand...
Click to collapse
- Create new Android Studio Project, then open AndroidManifest.xml to add PinP attributes.
(I suggest to create specific Activity to handle PinP)
Code:
<activity
android:name=".PictureInPicture.PinP"
android:label="@string/title_activity_pin_p"
[B][COLOR="Blue"]android:resizeableActivity="true"
android:supportsPictureInPicture="true"[/COLOR][/B]
android:theme="@android:style/Theme.DeviceDefault.Wallpaper.NoTitleBar" />
<!-- I used Wallpaper theme cause in my case I want to have transparent background that shows home launcher wallpaper -->
- Now Open your PinP Activity, PinP.java
The layout your design for this activity will show inside PinP Window.
(Here I set 3 ImageViews to load icons of selected apps that I load from a saved file)
To enter PinP Mode your need only to call this activity.enterPictureInPictureMode(); But you should add some functionality to it. READ COMMENTS IN CODE
Code:
public void enterPinP(){
[COLOR="Red"]//load packageNames from saved file[/COLOR]
List<String> appShortcutsPackageName = Arrays.asList(functionsClass.readFileLine(".autoSuper"));
[COLOR="red"]//set icon of apps to imageView[/COLOR]
imageViewOne.setImageBitmap(appIconBitmap(appShortcutsPackageName.get(0)));
imageViewTwo.setImageBitmap(appIconBitmap(appShortcutsPackageName.get(1)));
imageViewThree.setImageBitmap(appIconBitmap(appShortcutsPackageName.get(2)));
[COLOR="red"]//get main intent of apps[/COLOR]
Intent intentOne = getPackageManager().getLaunchIntentForPackage(appShortcutsPackageName.get(0)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Intent intentTwo = getPackageManager().getLaunchIntentForPackage(appShortcutsPackageName.get(1)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Intent intentThree = getPackageManager().getLaunchIntentForPackage(appShortcutsPackageName.get(2)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
[COLOR="red"]//create pending intent for actions on PinP Window [/COLOR]
[COLOR="red"]//you can also [b]getService()[/b] & [b]getBroadcast()[/b] [/COLOR]
final PendingIntent pendingIntentOne = PendingIntent.getActivity(getApplicationContext(), 333, intentOne,0);
final PendingIntent pendingIntentTwo = PendingIntent.getActivity(getApplicationContext(), 666, intentTwo,0);
final PendingIntent pendingIntentThree = PendingIntent.getActivity(getApplicationContext(), 999, intentThree,0);
[COLOR="red"]//here I add icon from resource to indicate where to click on PinP Window[/COLOR]
final Icon oneIcon = Icon.createWithResource(getApplicationContext(), R.drawable.ic_click);
final Icon twoIcon = Icon.createWithResource(getApplicationContext(), R.drawable.ic_click);
final Icon threeIcon = Icon.createWithResource(getApplicationContext(), R.drawable.ic_click);
[COLOR="red"]//remote actions to handle click from PinP Window[/COLOR]
final ArrayList<RemoteAction> remoteActions = new ArrayList<>();
remoteActions.add(new RemoteAction(oneIcon, appName(appShortcutsPackageName.get(0)), appName(appShortcutsPackageName.get(0)), pendingIntentOne));
remoteActions.add(new RemoteAction(twoIcon, appName(appShortcutsPackageName.get(1)), appName(appShortcutsPackageName.get(1)), pendingIntentTwo));
remoteActions.add(new RemoteAction(threeIcon, appName(appShortcutsPackageName.get(2)), appName(appShortcutsPackageName.get(2)), pendingIntentThree));
//
final PictureInPictureParams.Builder pictureInPictureParamsBuilder = new PictureInPictureParams.Builder();
pictureInPictureParamsBuilder.setActions(remoteActions);
pictureInPictureParamsBuilder.setAspectRatio(new Rational(50, 100));
PictureInPictureParams pictureInPictureParams = pictureInPictureParamsBuilder.build();
[B][COLOR="red"]//This is Main Functions. That you can Call from any Activity [/COLOR]
[COLOR="RoyalBlue"]enterPictureInPictureMode(pictureInPictureParams);[/COLOR][/B]
}
So wherever you call this function, it will enter to Picture in Picture Mode.
For Example, when click a button or @onPause() to continue showing some data.
I call it from onCreate(Bundle bundle) cause I create an activity specific for PinP Mode.
Also, you can recognize whenever your activity enter full screen mode Or PinP by overriding this functions
It is good way to add/remove views If you are using same activity for both full screen and PinP mode.
Code:
@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration configuration) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode, configuration);
if (isInPictureInPictureMode){
//picture in picture mode
}
else {
//full screen mode
}
}
Note: Limited amount of RemoteActions can be set for PinP Mode that you can get it from activity.getMaxNumPictureInPictureActions();
Oo. Download | PinP Shortcuts .oO
Super Shortcuts | Available in Beta Stage
Feel Free to Ask for Promo Code
Thanks for Support my Projects​Don't forget to Hit Thanks​
PinP Shortcuts | Extra Functions
Extra Functions Used in Tutorial​
Code:
public Bitmap [B]appIconBitmap[/B](String pack){
Bitmap bitmap = null;
try{
Drawable drawableIcon = context.getPackageManager().getApplicationIcon(pack);
if (drawableIcon instanceof BitmapDrawable) {
bitmap = ((BitmapDrawable)drawableIcon).getBitmap();
}
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (drawableIcon instanceof AdaptiveIconDrawable){
Drawable backgroundDrawable = ((AdaptiveIconDrawable) drawableIcon).getBackground();
Drawable foregroundDrawable = ((AdaptiveIconDrawable) drawableIcon).getForeground();
Drawable[] drawables = new Drawable[2];
drawables[0] = backgroundDrawable;
drawables[1] = foregroundDrawable;
LayerDrawable layerDrawable = new LayerDrawable(drawables);
int width = layerDrawable.getIntrinsicWidth();
int height = layerDrawable.getIntrinsicHeight();
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
layerDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
layerDrawable.draw(canvas);
}
else{
bitmap = Bitmap.createBitmap(drawableIcon.getIntrinsicWidth(), drawableIcon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
}
}
else{
bitmap = Bitmap.createBitmap(drawableIcon.getIntrinsicWidth(), drawableIcon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
}
}
catch(Exception e){
e.printStackTrace();
}
return bitmap;
}
Code:
public String [B]appName[/B](String pack){
String Name = null;
try{
PackageManager packManager = context.getPackageManager();
ApplicationInfo app = context.getPackageManager().getApplicationInfo(pack, 0);
Name = packManager.getApplicationLabel(app).toString();
}
catch(Exception e){
e.printStackTrace();
}
return Name;
}
Thanks for Support my Projects​Don't forget to Hit Thanks​
Reserved

Categories

Resources