반응형

Create a simple drawing app for Android.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MyView(this));
    }
 
    public class MyView extends View {
        Paint paint = new Paint();
        boolean isDrawing = false;
        ArrayList<Float> coordinateList = new ArrayList<>(100);
        // Each ArrayList instance has a capacity. The capacity is the size of the array used to store
        // the elements in the list. It is always at least as large as the list size. As elements are
        //  added to an ArrayList, its capacity grows automatically. The details of the growth policy
        //  are not specified beyond the fact that adding an element has constant amortized time cost.
 
        MyView(Context context)
        {
            super(context);
            paint.setColor(Color.BLUE); // 0xff0000ff
            paint.setStrokeWidth(8);
        }
 
        @Override
        public void onDraw(Canvas canvas)
        {
            // ArrayList, Float[], float[]은 서로 직접 호환되지 않음.
            Float[] coordinateFloat = coordinateList.toArray(new Float[coordinateList.size()]);
            float[] coordinate = new float[coordinateFloat.length];
 
            for (int i = 0; i < coordinateFloat.length; i++)
            {
                coordinate[i] = coordinateFloat[i].floatValue();
            }
 
            // 특정 색으로 화면을 채우는 메서드
            // void drawRGB(int r, int g, int b)
            // void drawARGB(int a, int r, int g, int b)
            // void drawColor(int color)
            // void drawPaint(Paint paint)
            canvas.drawARGB(2552552550); // Yellow
            canvas.drawLines(coordinate, paint);
            // Draw a series of lines. Each line is taken from 4 consecutive values in the pts array.
            // Thus to draw 1 line, the array must contain at least 4 values. This is logically the
            // same as drawing the array as follows: drawLine(pts[0], pts[1], pts[2], pts[3]) followed
            // by drawLine(pts[4], pts[5], pts[6], pts[7]) and so on.
        }
 
        // drawLines()는 4개의 좌표를 이용해 1개의 직선을 그린다(x1, y1, x2, y2)
        // 1개의 직선을 그리고 다음 직선의 시작 좌표(x1, y1)에 이전 끝 좌표(x2, y2)가
        // 없다면 끊어진 선으로 그려지게 된다. 마우스를 뗄때는 다음 직선의 시작 좌표로
        // 넣어준 값 두 개(x1, y1)를 삭제 해야 한다.
        @Override
        public boolean onTouchEvent(MotionEvent event)
        {
            switch (event.getAction())
            {
                case MotionEvent.ACTION_DOWN:
                    coordinateList.add(event.getX());
                    coordinateList.add(event.getY());
                    isDrawing = true;
                    break;
 
                case MotionEvent.ACTION_MOVE:
                    if (isDrawing)  // 이 코드에서는 별 의미는 없는 if
                    {
                        coordinateList.add(event.getX());
                        coordinateList.add(event.getY());
 
                        coordinateList.add(event.getX());
                        coordinateList.add(event.getY());
                    }
 
                    invalidate();
                    break;
 
                case MotionEvent.ACTION_UP:
                    coordinateList.remove(coordinateList.size() -1);
                    coordinateList.remove(coordinateList.size() -1);
                    isDrawing = false;
                    break;
 
                default:
                    break;
            }
 
            return true;
        }
    }



Run the app and draw.



To simplify the code, you can also use Path. The result is the same.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MyView(this));
    }
 
    public class MyView extends View {
        Paint paint = new Paint();
        boolean isDrawing = false;
        Path path = new Path();
 
        MyView(Context context)
        {
            super(context);
            paint.setColor(Color.BLUE); // 0xff0000ff
            paint.setStyle(Paint.Style.STROKE); // Paint.Style.FILL(기본값)로 하면 채워진 도형이 그려진다
            paint.setStrokeWidth(8);
        }
 
        @Override
        public void onDraw(Canvas canvas)
        {
            canvas.drawARGB(2552552550);
            canvas.drawPath(path, paint);
        }
 
        @Override
        public boolean onTouchEvent(MotionEvent event)
        {
            switch (event.getAction())
            {
                case MotionEvent.ACTION_DOWN:
                    path.moveTo(event.getX(), event.getY());
                    isDrawing = true;
                    break;
 
                case MotionEvent.ACTION_MOVE:
                    if (isDrawing)
                    {
                        path.lineTo(event.getX(), event.getY());
                        invalidate();
                    }
                    break;
 
                case MotionEvent.ACTION_UP:
                    isDrawing = false;
                    break;
 
                default:
                    break;
            }
 
            return true;
        }
    }



반응형
Posted by J-sean
:
반응형

Handling multiple buttons with one listener.

한 개의 리스너로 여러개의 버튼을 처리할 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        findViewById(R.id.button1).setOnClickListener(myClick);
        findViewById(R.id.button2).setOnClickListener(myClick);
        findViewById(R.id.button3).setOnClickListener(myClick);
    }
 
    View.OnClickListener myClick = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.button1:
                    Toast.makeText(getApplicationContext(), "Button 1", Toast.LENGTH_SHORT).show();
                    break;
 
                case R.id.button2:
                    Toast.makeText(getApplicationContext(), "Button 2", Toast.LENGTH_SHORT).show();
                    break;
 
                case R.id.button3:
                    Toast.makeText(getApplicationContext(), "Button 3", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    };
}



반응형
Posted by J-sean
:
반응형

A notification is a message that Android displays outside your app's UI to provide the user with reminders, communication from other people, or other timely information from your app. Users can tap the notification to open your app or take an action directly from the notification.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
public class MainActivity extends AppCompatActivity {
 
    NotificationManager notificationManager;
 
    private static String CHANNEL1_ID = "Channel1_ID";
    private static String CHANNEL1_NAME = "Channel1_NAME";
 
    private static String CHANNEL2_ID = "Channel2_ID";
    private static String CHANNEL2_NAME = "Channel2_NAME";
 
    private final int RequestCode = 101;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ShowNotification1();
            }
        });
 
        Button button2 = findViewById(R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ShowNotification2();
            }
        });
    }
 
    public void ShowNotification1() {
        notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        NotificationCompat.Builder builder = null;
 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (notificationManager.getNotificationChannel(CHANNEL1_ID) == null) {
                notificationManager.createNotificationChannel(new NotificationChannel(CHANNEL1_ID, CHANNEL1_NAME, NotificationManager.IMPORTANCE_DEFAULT));
                builder = new NotificationCompat.Builder(this, CHANNEL1_ID);
            } else {
                builder = new NotificationCompat.Builder(this, CHANNEL1_ID);
            }
        } else {
            builder = new NotificationCompat.Builder(this);
            // This package is part of the Android support library which is no longer maintained.
        }
 
        builder.setContentTitle("Simple notification");
        builder.setContentText("Message for simple notification");
        builder.setSmallIcon(android.R.drawable.ic_menu_view);
 
        Notification notification = builder.build();
 
        notificationManager.notify(1, notification);
        // Post a notification to be shown in the status bar. If a notification with the same id has already been posted by your application and has not yet
        // been canceled, it will be replaced by the updated information.
        // - Parameters
        // id: An identifier for this notification unique within your application.
        // notification: A Notification object describing what to show the user. Must not be null.
    }
 
    public void ShowNotification2() {
        notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        NotificationCompat.Builder builder = null;
 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (notificationManager.getNotificationChannel(CHANNEL2_ID) == null) {
                notificationManager.createNotificationChannel(new NotificationChannel(CHANNEL2_ID, CHANNEL2_NAME, NotificationManager.IMPORTANCE_DEFAULT));
                builder = new NotificationCompat.Builder(this, CHANNEL2_ID);
            } else {
                builder = new NotificationCompat.Builder(this, CHANNEL2_ID);
            }
        } else {
            builder = new NotificationCompat.Builder(this);
        }
 
        Uri uri = Uri.parse("https://s-engineer.tistory.com");
        Intent intent = new Intent(ACTION_VIEW, uri);
        // ACTION_VIEW: Display the data to the user. This is the most common action performed on data -- it is the generic action you can use on a piece of
        // data to get the most reasonable thing to occur. For example, when used on a contacts entry it will view the entry; when used on a mailto: URI it
        // will bring up a compose window filled with the information supplied by the URI; when used with a tel: URI it will invoke the dialer.
        PendingIntent pendingIntent = PendingIntent.getActivity(this, RequestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
 
        builder.setContentTitle("Notification with PendingIntent");
        builder.setContentText("Message for notification with PendingIntent");
        builder.setSmallIcon(android.R.drawable.ic_menu_view);
        builder.setAutoCancel(true);
        // Setting this flag will make it so the notification is automatically canceled when the user clicks it in the panel.
        builder.setContentIntent(pendingIntent);
        // Supply a PendingIntent to send when the notification is clicked.
 
        Notification notification = builder.build();
 
        notificationManager.notify(2, notification);
    }
}




Run the app and click "SIMPLE NOTIFICATION" button.


A simple notification appears as an icon in the status bar. Users can swipe down on the status bar to open the notification drawer, where they can view more details and take actions with the notification.


Go back to the app and click "NOTIFICATION WITH PENDINGINTENT" button. Then click the notification again.


It will take you to a great blog.


반응형
Posted by J-sean
:
반응형

freeglut을 설치하고 간단한 OpenGL 예제를 만들어 보자.


http://freeglut.sourceforge.net/ 에서 MSVC용 Prepackaged Release 를 다운 받아 원하는 폴더에 설치 한다.


빈 Console 프로젝트를 만든다.


freeglut 라이브러리의 dll 파일이 있는 폴더를 Environment에 지정 한다.


Include 디렉토리를 지정 한다.


sprintf() 사용을 위해 SDL checks를 No로 바꾼다. Yes로 된 경우 비표준 함수인 sprintf_s()를 써야 한다.


SDL checks: Adds recommended Security Development Lifecycle (SDL) checks. These checks include extra security-relevant warnings as errors, and additional secure code-generation features.


Library 디렉토리를 지정 한다.


외부 라이브러리 사용시 위 사진과 같이 라이브러리 파일들을 추가해야 하지만 freeglut_std.h에 필요한 라이브러리가 모두 추가 되어 있으므로 하지 않아도 된다.



<freeglut_std.h>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#   include <windows.h>
 
/* Windows static library */
#   ifdef FREEGLUT_STATIC
 
#error Static linking is not supported with this build. Please remove the FREEGLUT_STATIC preprocessor directive, or download the source code from http://freeglut.sf.net/ and build against that.
 
/* Windows shared library (DLL) */
#   else
 
#       define FGAPIENTRY __stdcall
#       if defined(FREEGLUT_EXPORTS)
#           define FGAPI __declspec(dllexport)
#       else
#           define FGAPI __declspec(dllimport)
 
            /* Link with Win32 shared freeglut lib */
#           if FREEGLUT_LIB_PRAGMAS
#             pragma comment (lib, "freeglut.lib")
#           endif
 
#       endif
 
#   endif
 
/* Drag in other Windows libraries as required by FreeGLUT */
#   if FREEGLUT_LIB_PRAGMAS
#       pragma comment (lib, "glu32.lib")    /* link OpenGL Utility lib     */
#       pragma comment (lib, "opengl32.lib"/* link Microsoft OpenGL lib   */
#       pragma comment (lib, "gdi32.lib")    /* link Windows GDI lib        */
#       pragma comment (lib, "winmm.lib")    /* link Windows MultiMedia lib */
#       pragma comment (lib, "user32.lib")   /* link Windows user lib       */
#   endif
 
#else
 
/* Non-Windows definition of FGAPI and FGAPIENTRY  */
#        define FGAPI
#        define FGAPIENTRY
 
#endif


windows.h 도 포함 되어 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include <gl/glut.h>
#include <cstdio>
 
GLfloat locationX = 0.0f, locationY = 0.0f;
const GLfloat step = 0.02f;
const GLfloat size = 0.2f;
int winId;
 
void Menu(int value);
void Keyboard(unsigned char key, int x, int y);
void Special(int key, int x, int y);
void Mouse(int button, int state, int x, int y);
void Display();
 
int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    
    winId = glutCreateWindow("OpenGL");
 
    glutKeyboardFunc(Keyboard);
    glutSpecialFunc(Special);
    glutMouseFunc(Mouse);
 
    // Sub menu
    GLint SubMenu = glutCreateMenu(Menu);
    glutAddMenuEntry("Red"4);
    glutAddMenuEntry("Green"5);
    glutAddMenuEntry("Blue"6);
 
    // Menu
    glutCreateMenu(Menu);
    glutAddMenuEntry("White"1);
    glutAddMenuEntry("Black"2);
    glutAddMenuEntry("Gray"3);
 
    // Add sub menu
    glutAddSubMenu("Triangle Color", SubMenu);
    glutAttachMenu(GLUT_RIGHT_BUTTON);
 
    glutDisplayFunc(Display);
 
    glutMainLoop();
 
    return 0;
}
 
void Menu(int value)
{
    switch (value) {
    case 1:
        glClearColor(1.0f1.0f1.0f1.0f);    // 배경 흰색
 
        break;
    case 2:
        glClearColor(0.0f0.0f0.0f1.0f);    // 배경 검정색
 
        break;
    case 3:
        glClearColor(0.5f0.5f0.5f1.0f);    // 배경 회색
 
        break;
    case 4:
        glColor3f(1.0f0.0f0.0f);            // 삼감형 빨간색
 
        break;
    case 5:
        glColor3f(0.0f1.0f0.0f);            // 삼감형 녹색
 
        break;
    case 6:
        glColor3f(0.0f0.0f1.0f);            // 삼감형 파란색
 
        break;
    default:
 
        break;
    }
 
    glutPostRedisplay();
}
 
void Keyboard(unsigned char key, int x, int y)
{
    switch (key) {
    case 'r':
    case 'R':
        glClearColor(1.0f0.0f0.0f1.0f);    // 배경 빨간색
 
        break;
    case 'g':
    case 'G':
        glClearColor(0.0f1.0f0.0f1.0f);    // 배경 녹색
 
        break;
    case 'b':
    case 'B':
        glClearColor(0.0f0.0f1.0f1.0f);    // 배경 파란색
 
        break;
    case 27:
        glutDestroyWindow(winId);                // ESC키 프로그램 종료
        exit(0);
 
        break;
    default:
 
        break;
    }
 
    glutPostRedisplay();
}
 
void Special(int key, int x, int y)
{
    switch (key) {
    case GLUT_KEY_LEFT:        // step 만큼 x감소
        locationX -= step;
 
        break;
    case GLUT_KEY_RIGHT:    // step 만큼 x증가
        locationX += step;
 
        break;
    case GLUT_KEY_UP:        // step 만큼 y증가
        locationY += step;
 
        break;
    case GLUT_KEY_DOWN:        // step 만큼 y감소
        locationY -= step;
 
        break;
    }
    char title[128= {0,};
    sprintf(title, "Triangle location (%.2f, y=%.2f)", locationX, locationY);
    glutSetWindowTitle(title); // 제목표시줄에 삼각형 좌표 표시
 
    glutPostRedisplay();
}
 
void Mouse(int button, int state, int x, int y)
{
    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
        glColor3f(0.0f1.0f1.0f);    // 삼각형 하늘색
        char title[128= { 0, };
        sprintf(title, "Click (x: %d, y: %d)", x, y);
        glutSetWindowTitle(title); // 제목표시줄에 클릭 좌표 표시
 
        glutPostRedisplay();
    }
    else if (button == GLUT_LEFT_BUTTON && state == GLUT_UP){
        glColor3f(1.0f1.0f0.0f);    // 삼각형 노란색
 
        glutPostRedisplay();
    }
}
 
 
void Display()
{
    glClear(GL_COLOR_BUFFER_BIT);
        
    glBegin(GL_TRIANGLES);
    glVertex2f(locationX, locationY + size);
    glVertex2f(locationX - size, locationY - size);
    glVertex2f(locationX + size, locationY - size);
    glEnd();
 
    glFinish();
}


코드를 입력하고 실행 한다.


오른쪽 버튼을 클릭하면 메뉴가 나온다.


삼각형이 빨간색으로 바뀌었다.


r,g,b, 방향키, ESC키 등을 눌러 본다.


SubSystem을Console에서 Widows로 바꾼다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <gl/glut.h>
 
void Menu(int value)
{
    switch (value) {
    case 1:
        glClearColor(1.0f1.0f1.0f1.0f);
 
        break;
    case 2:
        glClearColor(0.0f0.0f0.0f1.0f);
 
        break;
    case 3:
        glClearColor(0.5f0.5f0.5f1.0f);
 
        break;
    case 4:
        glColor3f(1.0f0.0f0.0f);
 
        break;
    case 5:
        glColor3f(0.0f1.0f0.0f);
 
        break;
    case 6:
        glColor3f(0.0f0.0f1.0f);
 
        break;
    default:
 
        break;
    }
 
    glutPostRedisplay();
}
 
void display() {
    glClear(GL_COLOR_BUFFER_BIT);
 
    glBegin(GL_TRIANGLES);
    glVertex2f(0.0f0.5f);
    glVertex2f(-0.5f-0.5f);
    glVertex2f(0.5f-0.5f);
    glEnd();
 
    glFinish();
}
 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
    glutCreateWindow("OpenGL");
 
    // Sub menu
    GLint SubMenu = glutCreateMenu(Menu);
    glutAddMenuEntry("Red"4);
    glutAddMenuEntry("Green"5);
    glutAddMenuEntry("Blue"6);
 
    // Menu
    glutCreateMenu(Menu);
    glutAddMenuEntry("White"1);
    glutAddMenuEntry("Black"2);
    glutAddMenuEntry("Gray"3);
 
    // Add sub menu
    glutAddSubMenu("Triangle Color", SubMenu);
    glutAttachMenu(GLUT_RIGHT_BUTTON);
 
    glutDisplayFunc(display);
 
    glutMainLoop();
 
    return 0;
}


위 코드와 같이 Windows 프로그램에 맞게 바꾸고 빌드하면 에러없이 빌드는 되지만 아무것도 실행 되지는 않는다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <Windows.h>
#include <gl/gl.h>
 
# pragma comment (lib, "opengl32.lib")
# pragma comment(lib, "glu32.lib")
 
HINSTANCE g_hInst;
HWND hWndMain;
LPCTSTR lpszClass = TEXT("OpenGL");
HDC hdc;
HGLRC hrc;
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void Display();
 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
    HWND hWnd;
    MSG Message;
    WNDCLASS WndClass;
    g_hInst = hInstance;
 
    WndClass.cbClsExtra = 0;
    WndClass.cbWndExtra = 0;
    WndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    WndClass.hInstance = hInstance;
    WndClass.lpfnWndProc = WndProc;
    WndClass.lpszClassName = lpszClass;
    WndClass.lpszMenuName = NULL;
    WndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    RegisterClass(&WndClass);
 
    hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, (HMENU)NULL, hInstance, NULL);
    ShowWindow(hWnd, nCmdShow);
 
    while (GetMessage(&Message, NULL00)) {
        TranslateMessage(&Message);
        DispatchMessage(&Message);
    }
 
    return (int)Message.wParam;
}
 
void Display()
{
    glClear(GL_COLOR_BUFFER_BIT);
 
    glBegin(GL_TRIANGLES);
    glVertex2f(0.0f0.5f);
    glVertex2f(-0.5f-0.5f);
    glVertex2f(0.5f-0.5f);
    glEnd();
 
    glFinish();
}
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    switch (iMessage) {
    case WM_CREATE:
        hWndMain = hWnd;
        PIXELFORMATDESCRIPTOR pfd;
        int nPixelFormat;
 
        hdc = GetDC(hWnd);
        memset(&pfd, 0sizeof(pfd));
 
        pfd.nSize = sizeof(pfd);
        pfd.nVersion = 1;
        pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
        pfd.iPixelType = PFD_TYPE_RGBA;
        pfd.cColorBits = 32;
 
        nPixelFormat = ChoosePixelFormat(hdc, &pfd);
        SetPixelFormat(hdc, nPixelFormat, &pfd);
 
        hrc = wglCreateContext(hdc);
        wglMakeCurrent(hdc, hrc);
 
        return 0;
 
    case WM_PAINT:
        Display();
 
        SetTextColor(hdc, RGB(2552550));
        SetBkMode(hdc, TRANSPARENT);
        TextOutA(hdc, 1010"Windows OpenGL"14);
        
        ValidateRect(hWnd, NULL);
 
        return 0;
 
    case WM_SIZE:
        glViewport(00, LOWORD(lParam), HIWORD(lParam));
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
 
        glOrtho(-11-111-1);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
 
        return 0;
    case WM_DESTROY:
        wglMakeCurrent(hdc, NULL);
        wglDeleteContext(hrc);
        ReleaseDC(hWnd, hdc);
        PostQuitMessage(0);
 
        return 0;
    }
 
    return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}


glut을 사용하지 않고 Windows에서 지원하는 OpenGL 관련 wgl함수를 이용해 작성한 코드이다.



※ Reference

http://soen.kr/lecture/library/opengl/opengl-5.htm


반응형
Posted by J-sean
:
반응형

Add a vibration and a ringtone notification to your android application.


<AndroidManifest.xml>

1
    <uses-permission android:name="android.permission.VIBRATE"/>



<MainActivity.java>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Vibrator vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
 
                if (Build.VERSION.SDK_INT >= 26) {
                    vibrator.vibrate(VibrationEffect.createOneShot(100010));
                    // - public static VibrationEffect createOneShot (long milliseconds, int amplitude)
                    // Create a one shot vibration. One shot vibrations will vibrate constantly for the specified period of time at the specified amplitude, and then stop.
                    // milliseconds long: The number of milliseconds to vibrate. This must be a positive number.
                    // amplitude int: The strength of the vibration. This must be a value between 1 and 255, or DEFAULT_AMPLITUDE.
                } else {
                    vibrator.vibrate(1000);
                    // Vibrate constantly for the specified period of time.
                    // This method was deprecated in API level 26. Use vibrate(android.os.VibrationEffect) instead.
                }
            }
        });
 
        Button button2 = findViewById(R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Uri uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
                // - public static Uri getDefaultUri (int type)
                // Returns the Uri for the default ringtone of a particular type. Rather than returning the actual ringtone's sound Uri, this will return the symbolic Uri
                // which will resolved to the actual sound when played.
                // - public static final int TYPE_NOTIFICATION
                // Type that refers to sounds that are used for notifications.
                // Constant Value: 2 (0x00000002)
 
                Ringtone ringtone = RingtoneManager.getRingtone(getApplicationContext(), uri);
                // Returns a Ringtone for a given sound URI.
                // If the given URI cannot be opened for any reason, this method will attempt to fallback on another sound. If it cannot find any, it will return null.
 
                ringtone.play();
                // Plays the ringtone.
            }
        });
 
        Button button3 = findViewById(R.id.button3);
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MediaPlayer mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.media);
                // Convenience method to create a MediaPlayer for a given resource id. On success, prepare() will already have been called and must not be called again.
                // When done with the MediaPlayer, you should call release(), to free the resources. If not released, too many MediaPlayer instances will result in an exception.
 
                mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                    @Override
                    public void onCompletion(MediaPlayer mp) {
                        mp.release();
                        // Releases resources associated with this MediaPlayer object. It is considered good practice to call this method when you're done using the MediaPlayer.
                    }
                });
                // Interface definition for a callback to be invoked when playback of a media source has completed.
 
                mediaPlayer.start();
                // Starts or resumes playback. If playback had previously been paused, playback will continue from where it was paused. If playback had been stopped, or never
                // started before, playback will start at the beginning.
            }
        });
    }
}




Add a media file for MediaPlayer.


Run the app and click the buttons.


반응형
Posted by J-sean
:
반응형

Hue is the color portion of the model, expressed as a number from 0 to 360 degrees:

Red: falls between 0 and 60 degrees.

Yellow: falls between 61 and 120 degrees.

Green: falls between 121-180 degrees.

Cyan: falls between 181-240 degrees.

Blue: falls between 241-300 degrees.

Magenta: falls between 301-360 degrees.


For HSV, OpenCV Hue range is [0,179], Saturation range is [0,255] and Value range is [0,255]. Different software uses different scales. So if you are comparing OpenCV values with them, you need to normalize these ranges.


HSV(Hue)를 이용하면 RGB를 이용하는 것 보다 간단히 특정색을 검출할 수 있다. OpenCV의 Hue값은 0~179 이다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <opencv2/opencv.hpp>
 
using namespace std;
using namespace cv;
 
int lowerHue = 40, upperHue = 80;    // Green
Mat src, src_hsv, mask, dst;
 
void OnHueChenaged(int pos, void* userdata)
{
    Scalar lowerb(lowerHue, 1000);
    Scalar upperb(upperHue, 255255);
 
    inRange(src_hsv, lowerb, upperb, mask);
    // Checks if array elements lie between the elements of two other arrays.
 
    dst.setTo(0);    // 매번 초기화 해 주지 않으면 이전에 선택한 색과 겹친다.
    src.copyTo(dst, mask);
    // The method copies the matrix data to another matrix. Before copying the data, the method invokes: m.create(this->size(), this->type());
    // so that the destination matrix is reallocated if needed.While m.copyTo(m); works flawlessly, the function does not handle the case of a
    // partial overlap between the sourceand the destination matrices. When the operation mask is specified, if the Mat::create call shown above
    // reallocates the matrix, the newly allocated matrix is initialized with all zeros before copying the data.
 
    imshow("mask", mask);
    imshow("dst", dst);
}
 
int main(int argc, char** argv)
{
    src = imread("candies.jpg", IMREAD_COLOR);
    if (src.empty()) {
        cerr << "Image load failed." << endl;
        
        return -1;
    }
 
    imshow("src", src);
 
    cvtColor(src, src_hsv, COLOR_BGR2HSV);
 
    namedWindow("mask");
    createTrackbar("Lower Hue""mask"&lowerHue, 179, OnHueChenaged);
    createTrackbar("Upper Hue""mask"&upperHue, 179, OnHueChenaged);
    OnHueChenaged(NULLNULL);
 
    waitKey(0);
    
    return 0;
}




Original candy image.


Mask for green color.


Green candies detected.


반응형
Posted by J-sean
:
반응형

This is a Windows backend only function but you can simply copy or save the image displayed with cv::imshow().


cv::imshow()로 이미지를 출력할 때 출력된 이미지를 간단히 클립 보드에 복사하거나 파일로 저장 할 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <opencv2/opencv.hpp>
 
using namespace std;
using namespace cv;
 
int main(int argc, char** argv)
{
    Mat src = imread("matera.jpg");
    if (src.empty()) {
        cerr << "Image load failed." << endl;
 
        return 0;
    }
 
    imshow("src", src);
    
    waitKey(0);
    
    return 0;
}



[Windows backend only]

  • Pressing Ctrl+C will copy the image to the clipboard.
  • Pressing Ctrl+S will show a dialog to save the image




반응형
Posted by J-sean
:
반응형

Python comes preinstalled on most Linux distributions and is available as a package on all others. However, there are certain features you might want to use that are not available on your distro’s package. You can easily compile the latest version of Python from the source.


대부분의 리눅스에는 파이썬이 포함되어 있어 바로 사용할 수 있지만 최신 버전의 파이썬 소스를 직접 컴파일해 사용할 수 도 있다.


파이썬 홈페이지에서 소스 파일 링크 주소를 확인 한다.


wget으로 소스코드를 다운 받는다.


다운 받은 소스 코드 확인.


--enable-optimizations 옵션과 함께 configure를 실행 한다.


make가 없다면 설치 한다.



make로 컴파일 한다. 지정된 디렉토리에 설치 하고 싶다면 make 실행 후 make altinstall 까지 진행 한다.


Warning: make install can overwrite or masquerade the python3 binary. make altinstall is therefore recommended instead of make install since it only installs exec_prefix/bin/pythonversion.


exec_prefix (${exec_prefix}) is installation-dependent and should be interpreted as for GNU software. For example, on most Linux systems, the default is /usr.


./python을 실행하면 컴파일된 파이썬이 실행 된다.


간단히 python명령어로 실행하기 위해 /usr/bin에 소프트 링크를 만들어 준다.


파이썬 홈페이지에서 다운 받았던 압축 파일은 삭제 한다.


dnf로 최신 버전 파이썬을 간단히 설치 할 수 도 있다.



설치가 완료되면 파이썬[버전] 형식으로 실행 할 수 있다.


Python package installer인 pip도 설치 한다. 


pip3 --version 명령으로 pip버전을 확인할 수 있다.


반응형
Posted by J-sean
: