diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index b5ca8bb37ca..59b92cff6ed 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -1470,6 +1470,16 @@ kotlinNativeInterop { defFile 'interop/basics/sockets.def' target 'native' } + + if (isMac()) { + opengl { + target 'native' + compilerOpts '-framework', 'OpenGL', '-framework', 'GLUT' + linkerOpts '-framework', 'OpenGL', '-framework', 'GLUT' + pkg 'opengl' + headers 'GLUT/glut.h' + } + } } task interop0(type: RunInteropKonanTest) { @@ -1504,3 +1514,11 @@ task interop_echo_server(type: RunInteropKonanTest) { source = "interop/basics/echo_server.kt" interop = 'sockets' } + +if (isMac()) { + task interop_opengl_teapot(type: RunInteropKonanTest) { + run = false + source = "interop/basics/opengl_teapot.kt" + interop = 'opengl' + } +} \ No newline at end of file diff --git a/backend.native/tests/interop/basics/opengl_teapot.kt b/backend.native/tests/interop/basics/opengl_teapot.kt new file mode 100644 index 00000000000..6b2a044c88f --- /dev/null +++ b/backend.native/tests/interop/basics/opengl_teapot.kt @@ -0,0 +1,116 @@ +import kotlinx.cinterop.* +import opengl.* + +// Ported from http://openglsamples.sourceforge.net/projects/index.php/blog/index/ + +private var rotation: GLfloat = 0.0f +private val rotationSpeed: GLfloat = 0.2f + +private val windowWidth = 640 +private val windowHeight = 480 + +fun display() { + // Clear Screen and Depth Buffer + glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) + glLoadIdentity() + + // Define a viewing transformation + gluLookAt(4.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) + + // Push and pop the current matrix stack. + // This causes that translations and rotations on this matrix wont influence others. + + glPushMatrix() + glColor3f(1.0f, 0.0f, 0.0f) + glTranslatef(0.0f, 0.0f, 0.0f) + glRotatef(rotation, 0.0f, 1.0f, 0.0f) + glRotatef(90.0f, 0.0f, 1.0f, 0.0f) + + // Draw the teapot + glutSolidTeapot(1.0) + glPopMatrix() + + + rotation += rotationSpeed + glutSwapBuffers() +} + + +fun initialize() { + // select projection matrix + glMatrixMode(GL_PROJECTION) + + // set the viewport + glViewport(0, 0, windowWidth, windowHeight) + + // set matrix mode + glMatrixMode(GL_PROJECTION) + + // reset projection matrix + glLoadIdentity() + val aspect = windowWidth.toDouble() / windowHeight + + // set up a perspective projection matrix + gluPerspective(45.0, aspect, 1.0, 500.0) + + // specify which matrix is the current matrix + glMatrixMode(GL_MODELVIEW) + glShadeModel(GL_SMOOTH) + + // specify the clear value for the depth buffer + glClearDepth(1.0) + glEnable(GL_DEPTH_TEST) + glDepthFunc(GL_LEQUAL) + + // specify implementation-specific hints + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) + + memScoped { + val ambLight: CArray = allocArrayOf(0.1f, 0.1f, 0.1f, 1.0f) + val diffuse: CArray = allocArrayOf(0.6f, 0.6f, 0.6f, 1.0f) + val specular: CArray = allocArrayOf(0.7f, 0.7f, 0.3f, 1.0f) + + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambLight[0].ptr) + glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse[0].ptr) + glLightfv(GL_LIGHT0, GL_SPECULAR, specular[0].ptr) + } + + + glEnable(GL_LIGHT0) + glEnable(GL_COLOR_MATERIAL) + glShadeModel(GL_SMOOTH) + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE) + glDepthFunc(GL_LEQUAL) + glEnable(GL_DEPTH_TEST) + glEnable(GL_LIGHTING) + glEnable(GL_LIGHT0) + glClearColor(0.0f, 0.0f, 0.0f, 1.0f) +} + +fun main(args: Array) { + // initialize and run program + memScoped { + val argc = alloc().apply { value = 0 } + glutInit(argc.ptr, null) // TODO: pass real args + } + + // Display Mode + glutInitDisplayMode(GLUT_RGB or GLUT_DOUBLE or GLUT_DEPTH) + + // Set window size + glutInitWindowSize(windowWidth, windowHeight) + + // create Window + glutCreateWindow("The GLUT Teapot") + + // register Display Function + glutDisplayFunc(staticCFunction(::display)) + + // register Idle Function + glutIdleFunc(staticCFunction(::display)) + + initialize() + + // run GLUT mainloop + glutMainLoop() +} \ No newline at end of file