본문 바로가기
Opengles 3.0 with Android

Chapter 1.3 Touch Event 받아서 Triangle 색상 변경해보기

by SimonLee 2024. 10. 15.

서피스 뷰에서 터치 이벤트 리스너를 등록하고 JNI로 이벤트를 내려주자.

TouchEventStart : 첫 터치 이벤트

TouchEventMove : 드래그 이벤트

TouchEventRelease : 마지막 터치 이벤트

 

GLESView.java

class GLESView extends GLSurfaceView {
	....
    public boolean onTouchEvent( final MotionEvent event )
    {
        //Log.w(TAG, "OnTouchEvent");

        switch( event.getAction() )
        {
            case MotionEvent.ACTION_DOWN:
            {
                GLESNativeLib.TouchEventStart( event.getX(0), event.getY(0));
                break;
            }

            case MotionEvent.ACTION_MOVE:
            {
                GLESNativeLib.TouchEventMove( event.getX(0), event.getY(0) );
                break;
            }

            case MotionEvent.ACTION_UP:
            {
                GLESNativeLib.TouchEventRelease( event.getX(0), event.getY(0) );
                break;
            }
        }

        return true;
    }
}


GLESNativeLib.java

package cookbook.gles;

public class GLESNativeLib {

    static {
        System.loadLibrary("glNative");
    }

    /**
     * @param width the current opengl view window width
     * @param height the current opengl view window view height
     */
    public static native void init( String apkFilePath );
    public static native void resize(int width, int height );
    public static native void step();

    public static native void TouchEventStart( float x, float y );
    public static native void TouchEventMove( float x, float y );
    public static native void TouchEventRelease( float x, float y );

}

 

 

NativeTemplate.cpp

#include "NativeTemplate.h"
#include "../Scene/renderer.h"

bool GraphicsInit()
{
    Renderer::Instance().initializeRenderer();
    return true;
}

bool GraphicsResize( int width, int height )
{
    Renderer::Instance().resize(width, height);
    return true;
}

bool GraphicsRender()
{
    Renderer::Instance().setUpProjection();
    Renderer::Instance().render();
    return true;
}

void TouchEventDown( float x, float y )
{
    Renderer::Instance().TouchEventDown( x, y );
}

void TouchEventMove( float x, float y )
{
    Renderer::Instance().TouchEventMove( x, y );
}

void TouchEventRelease( float x, float y )
{
    Renderer::Instance().TouchEventRelease( x, y );
}
#ifdef __ANDROID__

JNIEXPORT void JNICALL Java_cookbook_gles_GLESNativeLib_init( JNIEnv *env, jobject obj, jstring FilePath )
{
	setenv( "FILESYSTEM", env->GetStringUTFChars( FilePath, NULL ), 1 );
	GraphicsInit();
}

JNIEXPORT void JNICALL Java_cookbook_gles_GLESNativeLib_resize( JNIEnv *env, jobject obj, jint width, jint height)
{
	GraphicsResize( width, height );
}

JNIEXPORT void JNICALL Java_cookbook_gles_GLESNativeLib_step(JNIEnv * env, jobject obj)
{
	GraphicsRender();
    //renderFrame();
}

JNIEXPORT void JNICALL Java_cookbook_gles_GLESNativeLib_TouchEventStart(JNIEnv * env, jobject obj, float x, float y )
{
	TouchEventDown(x ,y);
}

JNIEXPORT void JNICALL Java_cookbook_gles_GLESNativeLib_TouchEventMove(JNIEnv * env, jobject obj, float x, float y )
{
	TouchEventMove(x ,y);
}

JNIEXPORT void JNICALL Java_cookbook_gles_GLESNativeLib_TouchEventRelease(JNIEnv * env, jobject obj, float x, float y )
{
	TouchEventRelease(x ,y);
}
#endif

 

여기까지가 앱에서 터치이벤트를 받아서 JNI를 통하여 네이티브로 전달을 했다.

 

 

앱이 실행되면 GraphicsInit() 가 실행되고

프레임마다 GraphicsRender() 실행되고,

마우스를 누를때마다 Touch Api () 실행 된다.

 

GraphicsInit() 과정에서

Triangle 객체를 생성 후 InitModel() 실행해 준다.

렌더 과정에는 Render() 실행해 준다.

 

InitModel() 에서는 앱이 실행하고 최초 1번 실행하니

셰이더 객체 생성, 셰이더 객체에 셰이더 코드 전달, 컴파일, Attach, 링킹 과 같은 작업을 진행한다.

Render() 에서는 프레임마다 실행되니

어트리뷰트 index 가져오고, 버퍼 데이터를 어트리뷰트에 연결,  셰이더 어트리뷰트 활성화 같은 작업을 진행 후

draw  한다.

 

터치 이벤트 down, move, release 발생할때마다 color 값을 바꾸어준다.

down 하면 빨강, move 하면 초록, release 하면 파랑으로 설정된다.

 

Triangle.cpp

Triangle::Triangle( Renderer* parent )
{
	if (!parent)
		return;

	MapRenderHandler	= parent;
	ProgramManagerObj	= parent->RendererProgramManager();
	TransformObj		= parent->RendererTransform();
	modelType 			= TriangleType;

	colors[0] = 0.0; colors[1] = 1.0; colors[2] = 0.0;
	colors[3] = 1.0; colors[4] = 0.0; colors[5] = 0.0;
	colors[6] = 0.0; colors[7] = 0.0; colors[8] = 1.0;
}

void Triangle::InitModel()
{
	if (!(program = ProgramManagerObj->Program( ( char * )"Triangle" ))) {
		program = ProgramManagerObj->ProgramInit( ( char * )"Triangle" );
		ProgramManagerObj->AddProgram( program );
	}

	program->VertexShader	= ShaderManager::ShaderInit( VERTEX_SHADER_PRG,	GL_VERTEX_SHADER	);
	program->FragmentShader	= ShaderManager::ShaderInit( FRAGMENT_SHADER_PRG, GL_FRAGMENT_SHADER	);

    //////////////////////////////////////////////////////
    /////////// Vertex shader //////////////////////////
    //////////////////////////////////////////////////////
	CACHE *m = reserveCache( VERTEX_SHADER_PRG, true );

	if( m ) {
		if( !ShaderManager::ShaderCompile( program->VertexShader, ( char * )m->buffer, 1 ) ) exit( 1 );
        freeCache( m );
	}

	m = reserveCache( FRAGMENT_SHADER_PRG, true );
	if( m ) {
		if( !ShaderManager::ShaderCompile( program->FragmentShader, ( char * )m->buffer, 1 ) ) exit( 2 );
        freeCache( m );
	}

    if( !ProgramManagerObj->ProgramLink( program, 1 ) ) exit( 3 );

    glUseProgram( program->ProgramID );

    return;
}

void Triangle::Render()
{
    glUseProgram( program->ProgramID );

	const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f };
	char attrib = ProgramManagerObj->ProgramGetVertexAttribLocation(program, (char*)"VertexPosition");
    glVertexAttribPointer(attrib, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
    glEnableVertexAttribArray(attrib);

	char attribColor = ProgramManagerObj->ProgramGetVertexAttribLocation(program, (char*)"VertexColor");
    glVertexAttribPointer(attribColor, 3, GL_FLOAT, GL_FALSE, 0, colors);
    glEnableVertexAttribArray(attribColor);


    glDrawArrays(GL_TRIANGLES, 0, 3);
}

void Triangle::TouchEventDown( float x, float y )
{
	colors[0] = 1.0; colors[1] = 0.0; colors[2] = 0.0;
	colors[3] = 1.0; colors[4] = 0.0; colors[5] = 0.0;
	colors[6] = 1.0; colors[7] = 0.0; colors[8] = 0.0;
}

void Triangle::TouchEventMove( float x, float y )
{
	colors[0] = 0.0; colors[1] = 1.0; colors[2] = 0.0;
	colors[3] = 0.0; colors[4] = 1.0; colors[5] = 0.0;
	colors[6] = 0.0; colors[7] = 1.0; colors[8] = 0.0;
}

void Triangle::TouchEventRelease( float x, float y )
{
	colors[0] = 0.0; colors[1] = 0.0; colors[2] = 1.0;
	colors[3] = 0.0; colors[4] = 0.0; colors[5] = 1.0;
	colors[6] = 0.0; colors[7] = 0.0; colors[8] = 1.0;
}

 

 

 

 

자주 실수하는 에러

1)

Android.mk에 Shared Library 를 빌드하도록 설정했으면

Application.mk 에서도 APP_STL := c++_shared로 설정하자.

include $(BUILD_SHARED_LIBRARY)

 

2) 

glAttachShader에서 에러가 나면 셰이더 컴파일이 제대로 동작하는지 확인하자.

보통은 셰이더 경로를 잘못써서 발생.

셰이더 폴더는 assets 폴더 내부에 보통 넣는다.

device/generic/goldfish-opengl/system/GLESv2_enc/GL2Encoder.cpp:s_glAttachShader:2155 GL error 0x501 condition [!shaderIsShaderOrProgram]

 

3) JNI cpp 코드에서 타입이 있는데, 리턴을 안하면 해당 함수에서 이유 없이 죽는다.

조심

00 pc 000000000000d061  /data/app/~~TeEzxj5I-

coAEqvSmqG0hA==/cookbook.opengles-0l8YZGEJFO1U5XJCcZLYjQ==/base.apk!libglNative.so (offset 0x6ba000) (GraphicsInit()+17)