Начнем с того, что сегодня самый лучший день для того, чтобы написать свое первое приложение для android. Если у Вас что-то не получалось до этого момента - будьте уверены, сегодня все получится!
И так. Вы установили новейшую версию Android Studio и все необходимые компоненты для работы с Android 4.4? Немного пощупали, изучили основные принципы работы в данной IDE и готовы покорять мир 3D графики? Отлично! Тогда приступим к работе.
В первую очередь создадим проект и назовем его OGLPart1.
Вы можете назвать его как угодно, но мне так будет удобнее. Уроков будет много и что бы не запутаться в них я буду нумеровать проекты эквивалентно статьям. Здесь все просто. Все, что от Вас требуется это указать имя проекта, папку для его хранения и минимальную поддерживаемую версию android. Стандартная процедура. [spoiler]
Теперь перед нами окно выбора шаблона приложения.
Я рекомендую Вам выбрать Blank Activity. В ином случае Вам может показаться, что в приложении много "лишнего" кода. Для начала этого вполне достаточно.
Диалог настройки активити
Он предложит нам сменить имя активити, заголовок .xml файла, содержащего его описание и прочие параметры.
Оставим все как есть. При желании все это можно сменить позже, так что не пугайтесь и не волнуйтесь если что-то сделали не так. Жмем кнопку "Finish" и через некоторое время перед нами появляется activity_main.xml файл. Точнее его графическое представление.
Снизу, под списком элементов, расположены две закладки: Design и Text. Если Вы будете нажимать на них(поверьте, Вы будете), то увидите, что с их помощью можно переключаться между графическим редактором интерфейса программы и кодом.
Слева Вы видите структурное дерево проекта. Именно там нужно выбирать файл для работы с ним. Сверху расположены различные элементы управления.
Интересными, в данный момент, для нас являются два:
Первый - зеленый треугольник. Эта кнопка служит для компиляции и запуска наших гениальных программ. Второй - это менеджер виртуальных устройств. Эмуляторов, говоря другими словами. Нажмем на него.
Перед нами появилось окно виртуальных устройств. Скорее всего, если Вы еще не создали ничего без меня, то список устройств будет пуст. Без паники! Это легко исправить. Кликаем по кнопке "Create Virtual Device..." и выставляем нужные нам настройки. Все просто!
/* Только не забываем, что минимальная версия Android на девайсе тоже должна быть 4.4. */
Готово! Теперь при нажатии на кнопку запуска приложения оно будет запускаться через наш эмулятор.
Перед тем как окунуться с головой в программирование нам нужно закинуть на форму специальный элемент GLSurfaceView. Именно он предназначен для работы с OpenGL командами и вывода изображения на дисплей устройства. Поищите его в списке элементов... Да, я тоже долго искал и думал, что просто не могу его заметить. Его там нет. Почему-то его не посчитали нужным вынести на панель, но мы это исправим.
Видите TextView с текстом "Hello, world!"? Мы превратим его в GLSurfaceView. Как Вам идея? Мне нравится, а у Вас все равно нет выбора, раз Вы до сих пор читаете.
/* Вообще, Вы можете сделать так с любым элементом или без элемента вообще, просто добавив нужный код в activity_main.xml */
Переходим в файл activity_main.xml и находим там описание TextView. Оно будет выглядеть примерно следующим образом:
Круто! У нас теперь есть настоящий GLSurfaceView с id glSurfaceView, растянутый на все окно. Почти... Остались зазоры по краям. Это происходит из-за того, что у RelativeLayout свойство padding по всем сторонам выставлено по умолчанию в 16dp. Что бы это исправить достаточно добавить в его описание такую строчку: android:padding="0dp"
/* Больше я не буду подробно останавливаться на интерфейсе Android Studio и том, что касается визуальной настройки приложения. Наша статья не об этом. Мы знакомимся с OpenGL 1.0. */
Переходим к файлу MainActivity.java.
Студия создала для нас несколько функций в классе MainActivity для удобства, но нам нужна только одна:
Остальное безжалостно удаляем и вот что у нас получается:
/*http://esate.ru, Freaky_Brainstorm(Brain Freaky)*/
package com.freakybrainstorm.oglpart1; /* Здесь у Вас будет название Вашего пакета. У каждого свое */
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
Здорово! Теперь, для взаимодействия с нашим GLSurfaceView необходимо создать переменную, хранящую его тип:
У класса GLSurfaceView есть метод setRenderer() который принимает в качестве параметра класс Renderer. Если мы хотим видеть что-то кроме черного экрана в нашем приложении, нам придется создать свой экземпляр этого класса. Приступим. Создадим новый класс и назовем его OpenGLRenderer:
/*http://esate.ru, Freaky_Brainstorm(Brain Freaky)*/
package com.freakybrainstorm.oglpart1;
import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class OpenGLRenderer implements GLSurfaceView.Renderer {
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
}
@Override
public void onSurfaceChanged(GL10 gl10, int i, int i1) {
}
@Override
public void onDrawFrame(GL10 gl10) {
}
}
Здесь все прекрасно, но параметры методов мне не нравяится и я всегда немного все переделываю до следующего вида:
/*http://esate.ru, Freaky_Brainstorm(Brain Freaky)*/
package com.freakybrainstorm.oglpart1;
import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class OpenGLRenderer implements GLSurfaceView.Renderer {
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) {
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
}
@Override
public void onDrawFrame(GL10 gl) {
}
}
/* Возможно, у Вас не будет необходимости в этом и Ваша Android Studio выдаст такой код сразу. */
Каракас нашей реализации класса Renderer готов. Следующим нашим шагом будет его "установка" в glSurfaceView, так что возвращаемся в класс MainActivity и после описания glSurfaceView добавляем следующий код:
/* Я намеренно вернул вас в класс MainActivity для того, чтобы Вы сразу подключили Renderer к glSurfaceView и не забыли о нем. А теперь я намеренно верну вас назад в класс OpenGLRenderer. */
Лучше некуда! Теперь это уже что-то похожее на реальное приложение, но оно совсем скучное и совсем ничего не делает. Мы с Вами совсем скоро это исправим, но, мне кажется, Вы хотите знать что значат все эти методы. И я Вам расскажу.
/*http://esate.ru, Freaky_Brainstorm(Brain Freaky)*/
public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig)
Этот метод вызывается при запуске приложения и всякий раз, при его перезапуске. В качестве параметров несет в себе GL10 - интерфейс OpenGL1.0 и EGLConfig - EGL конфигурация созданной поверхности(glSurfaceView).
/*http://esate.ru, Freaky_Brainstorm(Brain Freaky)*/
public void onSurfaceChanged(GL10 gl, int width, int height)
Этот метод вызывается при изменении размеров устройства вывода. В нашем случае это дисплей смартфона. В качестве параметров несет в себе GL10 - интерфейс OpenGL1.0 и размеры поверхности(glSurfaceView) экрана в переменных width и height.
/*http://esate.ru, Freaky_Brainstorm(Brain Freaky)*/
public void onDrawFrame(GL10 gl)
Этот метод вызывается для отрисовки текущего кадра. Для простоты можно сказать, что он постоянно работает и постоянно зациклен. В качестве параметров несет в себе GL10 - интерфейс OpenGL1.0.
Мы проделали уже не мало работы, но наше приложение так ничего и не рисует. Это слегка огорчает, не так ли? Обещаю, больше в этом уроке не будет ничего скучного. Мы начинаем КВН рисовать!
Весь код класса OpenGLRenderer:
/*http://esate.ru, Freaky_Brainstorm(Brain Freaky)*/
package com.freakybrainstorm.oglpart1;
import android.opengl.GLSurfaceView;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class OpenGLRenderer implements GLSurfaceView.Renderer {
private FloatBuffer vertexBuffer;
private float vertices[];
private float angle = 0.0f;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) {
//Устанавливаем цвет очистки("заливки") экрана в черный
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
//Устанавливаем X, Y, Z координаты точек вершин и записываем их в массив vertices
vertices = new float[]{
-0.5f, -0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f
};
//Создаем буфер вершин, содержащий наш массив
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
vertexBuffer = byteBuffer.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
//Устанавливаем область отрисовки
gl.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
//Очищаем буферы. В нашем случае буфер цвета и буфер глубины
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
//Включаем поддержку массивов вершин
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
//Устанавливаем цвет серый
gl.glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
//Указываем размер, тип и буфер с точками
//Третий параметр, который равен нулю, нас пока не интересует
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
//Рисуем по принципу GL_TRIANGLE_STRIP
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
//Сбрасываем матрицу(об этом ниже)
gl.glLoadIdentity();
//Вращаем текущую матрицу(наш объект, если сильно утрировать)
gl.glRotatef(angle, 1.0f, 1.0f, 1.0f);
angle++;
}
}
Теперь несколько слов по функции glLoadIdentity():
Эта функция умножает текущую матрицу на единичную и, говоря другими словами, "обнуляет" ее. Это нужно для того, что бы проделанные нами трансформации корректно отображались на экране. Наша переменная angle содержит сначала 1, затем 2, затем 3 и так далее. И в каждый кадр у нас происходит поворот на этот угол. Ели бы мы не сбрасывали матрицу, мы бы поворачивали объект ЕЩЕ НА 1, ЕЩЕ НА 2, ЕЩЕ НА 3 и т.д. градуса, а с применением glLoadIdentity() мы просто поворачиваем НА 1, НА 2, НА 3 и т.д. градуса. Надеюсь, это понятно. Если нет - попробуйте запустить код без glLoadIdentity().
На этом все. Ждите следующих статей
Понравилась публикация? Сохраните ее, чтобы вернуться к изучению материала!
при установке вылезла ошибка установки intel haxm в лог файле написано
This computer meets the requirements for HAXM, but Intel Virtualization Technology (VT-x) is not turned on. HAXM cannot be installed until VT-x is enabled. Please refer to the Intel HAXM documentation for more information.
C:\Users\zver\AppData\Local\Android\sdk\tools\emulator.exe -avd Nexus_4_API_23 -netspeed full -netdelay none emulator: ERROR: x86 emulation currently requires hardware acceleration! Please ensure Intel HAXM is properly installed and usable. CPU acceleration status: HAX kernel module is not installed! C:\Users\zver\AppData\Local\Android\sdk\tools\emulator.exe -avd Nexus_5_API_23_x86 -netspeed full -netdelay none emulator: ERROR: x86 emulation currently requires hardware acceleration! Please ensure Intel HAXM is properly installed and usable. CPU acceleration status: HAX kernel module is not installed!
content_main.xml это тоже самое, студия генерирует разные имена файлов в зависимости от версии SDK.
Это происходит из-за того, что у RelativeLayout свойство padding по всем сторонам выставлено по умолчанию в 16dp. Что бы это исправить достаточно добавить в его описание такую строчку: android:padding="0dp"
Я думал, это понятно Просто Вы мало знакомы с android studio
На счет зависимостей, да. Я их не указываю в статьях. Студия позволяет легко добавлять их сочетанием клавиш. У меня это ctrl + space
Сейчас в разработке следующая статья по матрицам. Разберем использование одновременно экранных и мировых координат.
Ждите)
Комментарии к статьям радуют не меньше
Я только пробую себя в написании статей, может есть какие-то пожелания или вопросы?)
в лог файле написано
This computer meets the requirements for HAXM, but Intel Virtualization Technology (VT-x) is not turned on. HAXM cannot be installed until VT-x is enabled.
Please refer to the Intel HAXM documentation for more information.
это не повредит выполнению уроков?
1.
в итоге: textview находится в content_main.xml, не в activity_main.xml
2.
android:padding="0dp" не сразу понятно, что надо добавлять в RelativeLayout, а не в android.opengl.GLSurfaceView
3. Сразу после того , как добавили
4. в итоге запуск без девайса не вышел.
C:\Users\zver\AppData\Local\Android\sdk\tools\emulator.exe -avd Nexus_4_API_23 -netspeed full -netdelay none
emulator: ERROR: x86 emulation currently requires hardware acceleration!
Please ensure Intel HAXM is properly installed and usable.
CPU acceleration status: HAX kernel module is not installed!
C:\Users\zver\AppData\Local\Android\sdk\tools\emulator.exe -avd Nexus_5_API_23_x86 -netspeed full -netdelay none
emulator: ERROR: x86 emulation currently requires hardware acceleration!
Please ensure Intel HAXM is properly installed and usable.
CPU acceleration status: HAX kernel module is not installed!
Это происходит из-за того, что у RelativeLayout свойство padding по всем сторонам выставлено по умолчанию в 16dp. Что бы это исправить достаточно добавить в его описание такую строчку: android:padding="0dp"
Я думал, это понятно Просто Вы мало знакомы с android studio
На счет зависимостей, да. Я их не указываю в статьях. Студия позволяет легко добавлять их сочетанием клавиш. У меня это ctrl + space
(подключил телефон и запустилось)
не совсем ясен код из MainActivity.java
что такое R.? это объект RelativeLayout?
Без отдельного курса по Android Studio конечно никак. Удобнее когда все на одном сайте
p.s. @admin форма отправки сообщения к кривой кнопкой (chrome,win7)
Кнопки переименовал и сделал разных цветов, т.к. даже сам часто щелкал на нижнюю, вместо того, чтобы отправить.