IDE perf tests for K/N: add more tests (Linux, AndroidNative)

This commit is contained in:
Dmitriy Dolovov
2020-03-03 16:37:05 +07:00
parent 80f2c091b4
commit 8635045a53
7 changed files with 789 additions and 5 deletions
@@ -16,11 +16,12 @@ import org.jetbrains.kotlin.gradle.KotlinSourceSet.Companion.COMMON_TEST_SOURCE_
import org.jetbrains.kotlin.ide.konan.NativeLibraryKind
import org.jetbrains.kotlin.idea.caches.project.isMPPModule
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil.parseIDELibraryName
import org.jetbrains.kotlin.idea.configuration.readGradleProperty
import org.jetbrains.kotlin.idea.facet.KotlinFacet
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
import org.jetbrains.kotlin.idea.framework.detectLibraryKind
import org.jetbrains.kotlin.idea.perf.PerformanceNativeProjectsTest.TestProject.*
import org.jetbrains.kotlin.idea.perf.PerformanceNativeProjectsTest.TestTarget.IOS
import org.jetbrains.kotlin.idea.perf.PerformanceNativeProjectsTest.TestTarget.*
import org.jetbrains.kotlin.idea.perf.Stats.Companion.WARM_UP
import org.jetbrains.kotlin.idea.perf.Stats.Companion.tcSuite
import org.jetbrains.kotlin.idea.testFramework.ProjectOpenAction.GRADLE_PROJECT
@@ -42,10 +43,11 @@ class PerformanceNativeProjectsTest : AbstractPerformanceProjectsTest() {
private var warmedUp: Boolean = false
}
private enum class TestTarget {
IOS;
private enum class TestTarget(val alias: String) {
IOS("ios"),
LINUX("linux"),
ANDROID_NATIVE("androidNative");
val alias get() = name.toLowerCase()
val enabled get() = true
}
@@ -67,6 +69,10 @@ class PerformanceNativeProjectsTest : AbstractPerformanceProjectsTest() {
UI_KIT_APP(
templateName = "UIKitApp",
filesToHighlight = listOf("src/main/UIKitApp.kt", "src/main/UIKitApp2.kt", "src/main/UIKitApp3.kt")
),
OPEN_GLES(
templateName = "OpenGLES",
filesToHighlight = listOf("src/main/App.kt", "src/main/App2.kt", "src/main/App3.kt")
);
init {
@@ -104,13 +110,26 @@ class PerformanceNativeProjectsTest : AbstractPerformanceProjectsTest() {
fun testIosHelloWorldProjectWithCommonizer() = doTestHighlighting(IOS, HELLO_WORLD, enableCommonizer = true)
fun testIosHelloWorldProjectWithoutCommonizer() = doTestHighlighting(IOS, HELLO_WORLD, enableCommonizer = false)
fun testAndroidNativeLinuxHelloWorldProjectWithCommonizer() = doTestHighlighting(ANDROID_NATIVE, HELLO_WORLD, enableCommonizer = true)
fun testAndroidNativeHelloWorldProjectWithoutCommonizer() = doTestHighlighting(ANDROID_NATIVE, HELLO_WORLD, enableCommonizer = false)
fun testLinuxHelloWorldProjectWithCommonizer() = doTestHighlighting(LINUX, HELLO_WORLD, enableCommonizer = true)
fun testLinuxHelloWorldProjectWithoutCommonizer() = doTestHighlighting(LINUX, HELLO_WORLD, enableCommonizer = false)
fun testIosCvsParserProjectWithCommonizer() = doTestHighlighting(IOS, CSV_PARSER, enableCommonizer = true)
fun testIosCvsParserProjectWithoutCommonizer() = doTestHighlighting(IOS, CSV_PARSER, enableCommonizer = false)
fun testAndroidNativeCvsParserProjectWithCommonizer() = doTestHighlighting(ANDROID_NATIVE, CSV_PARSER, enableCommonizer = true)
fun testAndroidNativeCvsParserProjectWithoutCommonizer() = doTestHighlighting(ANDROID_NATIVE, CSV_PARSER, enableCommonizer = false)
fun testLinuxCvsParserProjectWithCommonizer() = doTestHighlighting(LINUX, CSV_PARSER, enableCommonizer = true)
fun testLinuxCvsParserProjectWithoutCommonizer() = doTestHighlighting(LINUX, CSV_PARSER, enableCommonizer = false)
fun testIosUIKitAppProjectWithCommonizer() = doTestHighlighting(IOS, UI_KIT_APP, enableCommonizer = true)
fun testIosUIKitAppProjectWithoutCommonizer() = doTestHighlighting(IOS, UI_KIT_APP, enableCommonizer = false)
fun testIosOpenGLESWithCommonizer() = doTestHighlighting(IOS, OPEN_GLES, enableCommonizer = true)
fun testIosOpenGLESWithoutCommonizer() = doTestHighlighting(IOS, OPEN_GLES, enableCommonizer = false)
fun testAndroidNativeOpenGLESWithCommonizer() = doTestHighlighting(ANDROID_NATIVE, OPEN_GLES, enableCommonizer = true)
fun testAndroidNativeOpenGLESWithoutCommonizer() = doTestHighlighting(ANDROID_NATIVE, OPEN_GLES, enableCommonizer = false)
private fun doTestHighlighting(
testTarget: TestTarget,
testProject: TestProject,
@@ -218,14 +237,21 @@ class PerformanceNativeProjectsTest : AbstractPerformanceProjectsTest() {
// goal: make sure that the project imported from Gradle is valid
private fun runProjectSanityChecks(project: Project) {
val isNativeDependencyPropagationEnabled by lazy {
readGradleProperty(project, "kotlin.native.enableDependencyPropagation")?.toBoolean() == true
}
val nativeModules: Map<Module, Set<String>> = runReadAction {
project.allModules().mapNotNull { module ->
val facetSettings = KotlinFacet.get(module)?.configuration?.settings ?: return@mapNotNull null
if (!facetSettings.isMPPModule || !facetSettings.targetPlatform.isNative()) return@mapNotNull null
// ex: "myProject.commonTest" -> "commonTest"
val moduleName = module.name.removePrefix(project.name).removePrefix(".")
// workaround to skip top-level common test module, which in fact does not get any Kotlin/Native KLIB libraries
// but accidentally gets Kotlin facet with Native platform
if (module.name == "${project.name}.$COMMON_TEST_SOURCE_SET_NAME") return@mapNotNull null
if (moduleName == COMMON_TEST_SOURCE_SET_NAME) return@mapNotNull null
val nativeLibraries = module.rootManager.orderEntries
.asSequence()
@@ -246,6 +272,11 @@ class PerformanceNativeProjectsTest : AbstractPerformanceProjectsTest() {
}
.toSet()
// workaround to skip common Linux modules in "enabled dependency propagation" mode that do not
// get any Kotlin/Native KLIB libraries
if (nativeLibraries.isEmpty() && moduleName.startsWith("linux") && isNativeDependencyPropagationEnabled)
return@mapNotNull null
module to nativeLibraries
}.toMap()
}
@@ -0,0 +1 @@
// no project-specific settings
+234
View File
@@ -0,0 +1,234 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("RemoveRedundantCallsOfConversionMethods", "unused", "CanBeParameter")
import kotlinx.cinterop.FloatVar
import kotlinx.cinterop.allocArray
import kotlinx.cinterop.cValuesOf
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.set
import kotlinx.cinterop.toCValues
import platform.gles.GL_COLOR_BUFFER_BIT
import platform.gles.GL_CULL_FACE
import platform.gles.GL_CW
import platform.gles.GL_DEPTH_BUFFER_BIT
import platform.gles.GL_DEPTH_TEST
import platform.gles.GL_DIFFUSE
import platform.gles.GL_DITHER
import platform.gles.GL_FASTEST
import platform.gles.GL_FLOAT
import platform.gles.GL_FRONT_AND_BACK
import platform.gles.GL_LIGHT0
import platform.gles.GL_LIGHTING
import platform.gles.GL_MODELVIEW
import platform.gles.GL_NORMAL_ARRAY
import platform.gles.GL_PERSPECTIVE_CORRECTION_HINT
import platform.gles.GL_POSITION
import platform.gles.GL_PROJECTION
import platform.gles.GL_SHININESS
import platform.gles.GL_SMOOTH
import platform.gles.GL_SPECULAR
import platform.gles.GL_TEXTURE_2D
import platform.gles.GL_TEXTURE_COORD_ARRAY
import platform.gles.GL_TRIANGLES
import platform.gles.GL_UNSIGNED_BYTE
import platform.gles.GL_VERTEX_ARRAY
import platform.gles.glClear
import platform.gles.glClearColor
import platform.gles.glDisable
import platform.gles.glDrawElements
import platform.gles.glEnable
import platform.gles.glEnableClientState
import platform.gles.glFrontFace
import platform.gles.glFrustumf
import platform.gles.glHint
import platform.gles.glLightfv
import platform.gles.glLoadIdentity
import platform.gles.glMaterialf
import platform.gles.glMaterialfv
import platform.gles.glMatrixMode
import platform.gles.glMultMatrixf
import platform.gles.glNormalPointer
import platform.gles.glPopMatrix
import platform.gles.glPushMatrix
import platform.gles.glShadeModel
import platform.gles.glTexCoordPointer
import platform.gles.glTranslatef
import platform.gles.glVertexPointer
import platform.gles.glViewport
import platform.posix.sqrtf
private const val WIDTH = 600
private const val HEIGHT = 800
private const val SCALE = 1.25f
fun main() = memScoped {
glDisable(GL_DITHER)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST)
glClearColor(0.0f, 0.0f, 0.0f, 0.0f)
glEnable(GL_CULL_FACE)
glShadeModel(GL_SMOOTH)
glEnable(GL_DEPTH_TEST)
glViewport(0, 0, WIDTH, HEIGHT)
val ratio = WIDTH.toFloat() / HEIGHT
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glFrustumf(-ratio, ratio, -1.0f, 1.0f, 1.0f, 10.0f)
glMatrixMode(GL_MODELVIEW)
glTranslatef(0.0f, 0.0f, -2.0f)
glLightfv(GL_LIGHT0, GL_POSITION, cValuesOf(1.25f, 1.25f, -2.0f, 0.0f))
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_TEXTURE_2D)
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, cValuesOf(0.0f, 1.0f, 1.0f, 1.0f))
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, cValuesOf(0.3f, 0.3f, 0.3f, 1.0f))
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 30.0f)
glPushMatrix()
glMatrixMode(GL_MODELVIEW)
val matrix = allocArray<FloatVar>(16)
for (i in 0..3)
for (j in 0..3)
matrix[i * 4 + j] = if (i == j) 1.0f else 0.0f
glMultMatrixf(matrix)
glClear((GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT).toUInt())
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_NORMAL_ARRAY)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
val polygon = RegularPolyhedra.Dodecahedron
val vertices = mutableListOf<Float>()
val texCoords = mutableListOf<Float>()
val triangles = mutableListOf<Byte>()
val normals = mutableListOf<Float>()
val texturePoints = arrayOf(Vector2(0.0f, 0.2f), Vector2(0.0f, 0.8f), Vector2(0.6f, 1.0f), Vector2(1.0f, 0.5f), Vector2(0.8f, 0.0f))
for (face in polygon.faces) {
val u = polygon.vertices[face[2].toInt()] - polygon.vertices[face[1].toInt()]
val v = polygon.vertices[face[0].toInt()] - polygon.vertices[face[1].toInt()]
val normal = u.crossProduct(v).normalized()
val copiedFace = ByteArray(face.size)
for (j in face.indices) {
copiedFace[j] = (vertices.size / 4).toByte()
polygon.vertices[face[j].toInt()].copyCoordinatesTo(vertices)
vertices.add(SCALE)
normal.copyCoordinatesTo(normals)
texturePoints[j].copyCoordinatesTo(texCoords)
}
for (j in 1..face.size - 2) {
triangles.add(copiedFace[0])
triangles.add(copiedFace[j])
triangles.add(copiedFace[j + 1])
}
}
glFrontFace(GL_CW)
glVertexPointer(4, GL_FLOAT, 0, vertices.toFloatArray().toCValues().ptr)
glTexCoordPointer(2, GL_FLOAT, 0, texCoords.toFloatArray().toCValues().ptr)
glNormalPointer(GL_FLOAT, 0, normals.toFloatArray().toCValues().ptr)
glDrawElements(GL_TRIANGLES, triangles.size, GL_UNSIGNED_BYTE, triangles.toByteArray().toCValues().ptr)
glPopMatrix()
}
private class Vector2(val x: Float, val y: Float) {
val length by lazy { sqrtf(x * x + y * y) }
fun normalized(): Vector2 {
val len = length
return Vector2(x / len, y / len)
}
fun copyCoordinatesTo(arr: MutableList<Float>) {
arr.add(x)
arr.add(y)
}
operator fun minus(other: Vector2) = Vector2(x - other.x, y - other.y)
operator fun plus(other: Vector2) = Vector2(x + other.x, y + other.y)
operator fun times(other: Float) = Vector2(x * other, y * other)
operator fun div(other: Float) = Vector2(x / other, y / other)
companion object {
val Zero = Vector2(0.0f, 0.0f)
}
}
private class Vector3(val x: Float, val y: Float, val z: Float) {
val length by lazy { sqrtf(x * x + y * y + z * z) }
fun crossProduct(other: Vector3): Vector3 =
Vector3(y * other.z - z * other.y, z * other.x - x * other.z, x * other.y - y * other.x)
fun normalized(): Vector3 {
val len = length
return Vector3(x / len, y / len, z / len)
}
fun copyCoordinatesTo(arr: MutableList<Float>) {
arr.add(x)
arr.add(y)
arr.add(z)
}
operator fun minus(other: Vector3) = Vector3(x - other.x, y - other.y, z - other.z)
operator fun plus(other: Vector3) = Vector3(x + other.x, y + other.y, z + other.z)
}
private const val Zero = 0.0f
private const val DodeA = 0.93417235896f // (Sqrt(5) + 1) / (2 * Sqrt(3))
private const val DodeB = 0.35682208977f // (Sqrt(5) - 1) / (2 * Sqrt(3))
private const val DodeC = 0.57735026919f // 1 / Sqrt(3)
private const val IcosA = 0.52573111212f // Sqrt(5 - Sqrt(5)) / Sqrt(10)
private const val IcosB = 0.85065080835f // Sqrt(5 + Sqrt(5)) / Sqrt(10)
private enum class RegularPolyhedra(val vertices: Array<Vector3>, val faces: Array<ByteArray>) {
Dodecahedron(
arrayOf(
Vector3(-DodeA, Zero, DodeB), Vector3(-DodeA, Zero, -DodeB), Vector3(DodeA, Zero, -DodeB),
Vector3(DodeA, Zero, DodeB), Vector3(DodeB, -DodeA, Zero), Vector3(-DodeB, -DodeA, Zero),
Vector3(-DodeB, DodeA, Zero), Vector3(DodeB, DodeA, Zero), Vector3(Zero, DodeB, -DodeA),
Vector3(Zero, -DodeB, -DodeA), Vector3(Zero, -DodeB, DodeA), Vector3(Zero, DodeB, DodeA),
Vector3(-DodeC, -DodeC, DodeC), Vector3(-DodeC, -DodeC, -DodeC), Vector3(DodeC, -DodeC, -DodeC),
Vector3(DodeC, -DodeC, DodeC), Vector3(-DodeC, DodeC, DodeC), Vector3(-DodeC, DodeC, -DodeC),
Vector3(DodeC, DodeC, -DodeC), Vector3(DodeC, DodeC, DodeC)
),
arrayOf(
byteArrayOf(0, 12, 10, 11, 16), byteArrayOf(1, 17, 8, 9, 13), byteArrayOf(2, 14, 9, 8, 18),
byteArrayOf(3, 19, 11, 10, 15), byteArrayOf(4, 14, 2, 3, 15), byteArrayOf(5, 12, 0, 1, 13),
byteArrayOf(6, 17, 1, 0, 16), byteArrayOf(7, 19, 3, 2, 18), byteArrayOf(8, 17, 6, 7, 18),
byteArrayOf(9, 14, 4, 5, 13), byteArrayOf(10, 12, 5, 4, 15), byteArrayOf(11, 19, 7, 6, 16)
)),
Icosahedron(
arrayOf(
Vector3(-IcosA, Zero, IcosB), Vector3(IcosA, Zero, IcosB), Vector3(-IcosA, Zero, -IcosB),
Vector3(IcosA, Zero, -IcosB), Vector3(Zero, IcosB, IcosA), Vector3(Zero, IcosB, -IcosA),
Vector3(Zero, -IcosB, IcosA), Vector3(Zero, -IcosB, -IcosA), Vector3(IcosB, IcosA, Zero),
Vector3(-IcosB, IcosA, Zero), Vector3(IcosB, -IcosA, Zero), Vector3(-IcosB, -IcosA, Zero)
),
arrayOf(
byteArrayOf(1, 4, 0), byteArrayOf(4, 9, 0), byteArrayOf(4, 5, 9), byteArrayOf(8, 5, 4),
byteArrayOf(1, 8, 4), byteArrayOf(1, 10, 8), byteArrayOf(10, 3, 8), byteArrayOf(8, 3, 5),
byteArrayOf(3, 2, 5), byteArrayOf(3, 7, 2), byteArrayOf(3, 10, 7), byteArrayOf(10, 6, 7),
byteArrayOf(6, 11, 7), byteArrayOf(6, 0, 11), byteArrayOf(6, 1, 0), byteArrayOf(10, 1, 6),
byteArrayOf(11, 0, 9), byteArrayOf(2, 11, 9), byteArrayOf(5, 2, 9), byteArrayOf(11, 2, 7)
)
);
val verticesPerFace get() = faces[0].size
}
+234
View File
@@ -0,0 +1,234 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("RemoveRedundantCallsOfConversionMethods", "unused", "CanBeParameter")
import kotlinx.cinterop.FloatVar
import kotlinx.cinterop.allocArray
import kotlinx.cinterop.cValuesOf
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.set
import kotlinx.cinterop.toCValues
import platform.gles.GL_COLOR_BUFFER_BIT
import platform.gles.GL_CULL_FACE
import platform.gles.GL_CW
import platform.gles.GL_DEPTH_BUFFER_BIT
import platform.gles.GL_DEPTH_TEST
import platform.gles.GL_DIFFUSE
import platform.gles.GL_DITHER
import platform.gles.GL_FASTEST
import platform.gles.GL_FLOAT
import platform.gles.GL_FRONT_AND_BACK
import platform.gles.GL_LIGHT0
import platform.gles.GL_LIGHTING
import platform.gles.GL_MODELVIEW
import platform.gles.GL_NORMAL_ARRAY
import platform.gles.GL_PERSPECTIVE_CORRECTION_HINT
import platform.gles.GL_POSITION
import platform.gles.GL_PROJECTION
import platform.gles.GL_SHININESS
import platform.gles.GL_SMOOTH
import platform.gles.GL_SPECULAR
import platform.gles.GL_TEXTURE_2D
import platform.gles.GL_TEXTURE_COORD_ARRAY
import platform.gles.GL_TRIANGLES
import platform.gles.GL_UNSIGNED_BYTE
import platform.gles.GL_VERTEX_ARRAY
import platform.gles.glClear
import platform.gles.glClearColor
import platform.gles.glDisable
import platform.gles.glDrawElements
import platform.gles.glEnable
import platform.gles.glEnableClientState
import platform.gles.glFrontFace
import platform.gles.glFrustumf
import platform.gles.glHint
import platform.gles.glLightfv
import platform.gles.glLoadIdentity
import platform.gles.glMaterialf
import platform.gles.glMaterialfv
import platform.gles.glMatrixMode
import platform.gles.glMultMatrixf
import platform.gles.glNormalPointer
import platform.gles.glPopMatrix
import platform.gles.glPushMatrix
import platform.gles.glShadeModel
import platform.gles.glTexCoordPointer
import platform.gles.glTranslatef
import platform.gles.glVertexPointer
import platform.gles.glViewport
import platform.posix.sqrtf
private const val WIDTH = 600
private const val HEIGHT = 800
private const val SCALE = 1.25f
fun main() = memScoped {
glDisable(GL_DITHER)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST)
glClearColor(0.0f, 0.0f, 0.0f, 0.0f)
glEnable(GL_CULL_FACE)
glShadeModel(GL_SMOOTH)
glEnable(GL_DEPTH_TEST)
glViewport(0, 0, WIDTH, HEIGHT)
val ratio = WIDTH.toFloat() / HEIGHT
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glFrustumf(-ratio, ratio, -1.0f, 1.0f, 1.0f, 10.0f)
glMatrixMode(GL_MODELVIEW)
glTranslatef(0.0f, 0.0f, -2.0f)
glLightfv(GL_LIGHT0, GL_POSITION, cValuesOf(1.25f, 1.25f, -2.0f, 0.0f))
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_TEXTURE_2D)
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, cValuesOf(0.0f, 1.0f, 1.0f, 1.0f))
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, cValuesOf(0.3f, 0.3f, 0.3f, 1.0f))
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 30.0f)
glPushMatrix()
glMatrixMode(GL_MODELVIEW)
val matrix = allocArray<FloatVar>(16)
for (i in 0..3)
for (j in 0..3)
matrix[i * 4 + j] = if (i == j) 1.0f else 0.0f
glMultMatrixf(matrix)
glClear((GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT).toUInt())
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_NORMAL_ARRAY)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
val polygon = RegularPolyhedra.Dodecahedron
val vertices = mutableListOf<Float>()
val texCoords = mutableListOf<Float>()
val triangles = mutableListOf<Byte>()
val normals = mutableListOf<Float>()
val texturePoints = arrayOf(Vector2(0.0f, 0.2f), Vector2(0.0f, 0.8f), Vector2(0.6f, 1.0f), Vector2(1.0f, 0.5f), Vector2(0.8f, 0.0f))
for (face in polygon.faces) {
val u = polygon.vertices[face[2].toInt()] - polygon.vertices[face[1].toInt()]
val v = polygon.vertices[face[0].toInt()] - polygon.vertices[face[1].toInt()]
val normal = u.crossProduct(v).normalized()
val copiedFace = ByteArray(face.size)
for (j in face.indices) {
copiedFace[j] = (vertices.size / 4).toByte()
polygon.vertices[face[j].toInt()].copyCoordinatesTo(vertices)
vertices.add(SCALE)
normal.copyCoordinatesTo(normals)
texturePoints[j].copyCoordinatesTo(texCoords)
}
for (j in 1..face.size - 2) {
triangles.add(copiedFace[0])
triangles.add(copiedFace[j])
triangles.add(copiedFace[j + 1])
}
}
glFrontFace(GL_CW)
glVertexPointer(4, GL_FLOAT, 0, vertices.toFloatArray().toCValues().ptr)
glTexCoordPointer(2, GL_FLOAT, 0, texCoords.toFloatArray().toCValues().ptr)
glNormalPointer(GL_FLOAT, 0, normals.toFloatArray().toCValues().ptr)
glDrawElements(GL_TRIANGLES, triangles.size, GL_UNSIGNED_BYTE, triangles.toByteArray().toCValues().ptr)
glPopMatrix()
}
private class Vector2(val x: Float, val y: Float) {
val length by lazy { sqrtf(x * x + y * y) }
fun normalized(): Vector2 {
val len = length
return Vector2(x / len, y / len)
}
fun copyCoordinatesTo(arr: MutableList<Float>) {
arr.add(x)
arr.add(y)
}
operator fun minus(other: Vector2) = Vector2(x - other.x, y - other.y)
operator fun plus(other: Vector2) = Vector2(x + other.x, y + other.y)
operator fun times(other: Float) = Vector2(x * other, y * other)
operator fun div(other: Float) = Vector2(x / other, y / other)
companion object {
val Zero = Vector2(0.0f, 0.0f)
}
}
private class Vector3(val x: Float, val y: Float, val z: Float) {
val length by lazy { sqrtf(x * x + y * y + z * z) }
fun crossProduct(other: Vector3): Vector3 =
Vector3(y * other.z - z * other.y, z * other.x - x * other.z, x * other.y - y * other.x)
fun normalized(): Vector3 {
val len = length
return Vector3(x / len, y / len, z / len)
}
fun copyCoordinatesTo(arr: MutableList<Float>) {
arr.add(x)
arr.add(y)
arr.add(z)
}
operator fun minus(other: Vector3) = Vector3(x - other.x, y - other.y, z - other.z)
operator fun plus(other: Vector3) = Vector3(x + other.x, y + other.y, z + other.z)
}
private const val Zero = 0.0f
private const val DodeA = 0.93417235896f // (Sqrt(5) + 1) / (2 * Sqrt(3))
private const val DodeB = 0.35682208977f // (Sqrt(5) - 1) / (2 * Sqrt(3))
private const val DodeC = 0.57735026919f // 1 / Sqrt(3)
private const val IcosA = 0.52573111212f // Sqrt(5 - Sqrt(5)) / Sqrt(10)
private const val IcosB = 0.85065080835f // Sqrt(5 + Sqrt(5)) / Sqrt(10)
private enum class RegularPolyhedra(val vertices: Array<Vector3>, val faces: Array<ByteArray>) {
Dodecahedron(
arrayOf(
Vector3(-DodeA, Zero, DodeB), Vector3(-DodeA, Zero, -DodeB), Vector3(DodeA, Zero, -DodeB),
Vector3(DodeA, Zero, DodeB), Vector3(DodeB, -DodeA, Zero), Vector3(-DodeB, -DodeA, Zero),
Vector3(-DodeB, DodeA, Zero), Vector3(DodeB, DodeA, Zero), Vector3(Zero, DodeB, -DodeA),
Vector3(Zero, -DodeB, -DodeA), Vector3(Zero, -DodeB, DodeA), Vector3(Zero, DodeB, DodeA),
Vector3(-DodeC, -DodeC, DodeC), Vector3(-DodeC, -DodeC, -DodeC), Vector3(DodeC, -DodeC, -DodeC),
Vector3(DodeC, -DodeC, DodeC), Vector3(-DodeC, DodeC, DodeC), Vector3(-DodeC, DodeC, -DodeC),
Vector3(DodeC, DodeC, -DodeC), Vector3(DodeC, DodeC, DodeC)
),
arrayOf(
byteArrayOf(0, 12, 10, 11, 16), byteArrayOf(1, 17, 8, 9, 13), byteArrayOf(2, 14, 9, 8, 18),
byteArrayOf(3, 19, 11, 10, 15), byteArrayOf(4, 14, 2, 3, 15), byteArrayOf(5, 12, 0, 1, 13),
byteArrayOf(6, 17, 1, 0, 16), byteArrayOf(7, 19, 3, 2, 18), byteArrayOf(8, 17, 6, 7, 18),
byteArrayOf(9, 14, 4, 5, 13), byteArrayOf(10, 12, 5, 4, 15), byteArrayOf(11, 19, 7, 6, 16)
)),
Icosahedron(
arrayOf(
Vector3(-IcosA, Zero, IcosB), Vector3(IcosA, Zero, IcosB), Vector3(-IcosA, Zero, -IcosB),
Vector3(IcosA, Zero, -IcosB), Vector3(Zero, IcosB, IcosA), Vector3(Zero, IcosB, -IcosA),
Vector3(Zero, -IcosB, IcosA), Vector3(Zero, -IcosB, -IcosA), Vector3(IcosB, IcosA, Zero),
Vector3(-IcosB, IcosA, Zero), Vector3(IcosB, -IcosA, Zero), Vector3(-IcosB, -IcosA, Zero)
),
arrayOf(
byteArrayOf(1, 4, 0), byteArrayOf(4, 9, 0), byteArrayOf(4, 5, 9), byteArrayOf(8, 5, 4),
byteArrayOf(1, 8, 4), byteArrayOf(1, 10, 8), byteArrayOf(10, 3, 8), byteArrayOf(8, 3, 5),
byteArrayOf(3, 2, 5), byteArrayOf(3, 7, 2), byteArrayOf(3, 10, 7), byteArrayOf(10, 6, 7),
byteArrayOf(6, 11, 7), byteArrayOf(6, 0, 11), byteArrayOf(6, 1, 0), byteArrayOf(10, 1, 6),
byteArrayOf(11, 0, 9), byteArrayOf(2, 11, 9), byteArrayOf(5, 2, 9), byteArrayOf(11, 2, 7)
)
);
val verticesPerFace get() = faces[0].size
}
+234
View File
@@ -0,0 +1,234 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("RemoveRedundantCallsOfConversionMethods", "unused", "CanBeParameter")
import kotlinx.cinterop.FloatVar
import kotlinx.cinterop.allocArray
import kotlinx.cinterop.cValuesOf
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.set
import kotlinx.cinterop.toCValues
import platform.gles.GL_COLOR_BUFFER_BIT
import platform.gles.GL_CULL_FACE
import platform.gles.GL_CW
import platform.gles.GL_DEPTH_BUFFER_BIT
import platform.gles.GL_DEPTH_TEST
import platform.gles.GL_DIFFUSE
import platform.gles.GL_DITHER
import platform.gles.GL_FASTEST
import platform.gles.GL_FLOAT
import platform.gles.GL_FRONT_AND_BACK
import platform.gles.GL_LIGHT0
import platform.gles.GL_LIGHTING
import platform.gles.GL_MODELVIEW
import platform.gles.GL_NORMAL_ARRAY
import platform.gles.GL_PERSPECTIVE_CORRECTION_HINT
import platform.gles.GL_POSITION
import platform.gles.GL_PROJECTION
import platform.gles.GL_SHININESS
import platform.gles.GL_SMOOTH
import platform.gles.GL_SPECULAR
import platform.gles.GL_TEXTURE_2D
import platform.gles.GL_TEXTURE_COORD_ARRAY
import platform.gles.GL_TRIANGLES
import platform.gles.GL_UNSIGNED_BYTE
import platform.gles.GL_VERTEX_ARRAY
import platform.gles.glClear
import platform.gles.glClearColor
import platform.gles.glDisable
import platform.gles.glDrawElements
import platform.gles.glEnable
import platform.gles.glEnableClientState
import platform.gles.glFrontFace
import platform.gles.glFrustumf
import platform.gles.glHint
import platform.gles.glLightfv
import platform.gles.glLoadIdentity
import platform.gles.glMaterialf
import platform.gles.glMaterialfv
import platform.gles.glMatrixMode
import platform.gles.glMultMatrixf
import platform.gles.glNormalPointer
import platform.gles.glPopMatrix
import platform.gles.glPushMatrix
import platform.gles.glShadeModel
import platform.gles.glTexCoordPointer
import platform.gles.glTranslatef
import platform.gles.glVertexPointer
import platform.gles.glViewport
import platform.posix.sqrtf
private const val WIDTH = 600
private const val HEIGHT = 800
private const val SCALE = 1.25f
fun main() = memScoped {
glDisable(GL_DITHER)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST)
glClearColor(0.0f, 0.0f, 0.0f, 0.0f)
glEnable(GL_CULL_FACE)
glShadeModel(GL_SMOOTH)
glEnable(GL_DEPTH_TEST)
glViewport(0, 0, WIDTH, HEIGHT)
val ratio = WIDTH.toFloat() / HEIGHT
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glFrustumf(-ratio, ratio, -1.0f, 1.0f, 1.0f, 10.0f)
glMatrixMode(GL_MODELVIEW)
glTranslatef(0.0f, 0.0f, -2.0f)
glLightfv(GL_LIGHT0, GL_POSITION, cValuesOf(1.25f, 1.25f, -2.0f, 0.0f))
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_TEXTURE_2D)
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, cValuesOf(0.0f, 1.0f, 1.0f, 1.0f))
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, cValuesOf(0.3f, 0.3f, 0.3f, 1.0f))
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 30.0f)
glPushMatrix()
glMatrixMode(GL_MODELVIEW)
val matrix = allocArray<FloatVar>(16)
for (i in 0..3)
for (j in 0..3)
matrix[i * 4 + j] = if (i == j) 1.0f else 0.0f
glMultMatrixf(matrix)
glClear((GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT).toUInt())
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_NORMAL_ARRAY)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
val polygon = RegularPolyhedra.Dodecahedron
val vertices = mutableListOf<Float>()
val texCoords = mutableListOf<Float>()
val triangles = mutableListOf<Byte>()
val normals = mutableListOf<Float>()
val texturePoints = arrayOf(Vector2(0.0f, 0.2f), Vector2(0.0f, 0.8f), Vector2(0.6f, 1.0f), Vector2(1.0f, 0.5f), Vector2(0.8f, 0.0f))
for (face in polygon.faces) {
val u = polygon.vertices[face[2].toInt()] - polygon.vertices[face[1].toInt()]
val v = polygon.vertices[face[0].toInt()] - polygon.vertices[face[1].toInt()]
val normal = u.crossProduct(v).normalized()
val copiedFace = ByteArray(face.size)
for (j in face.indices) {
copiedFace[j] = (vertices.size / 4).toByte()
polygon.vertices[face[j].toInt()].copyCoordinatesTo(vertices)
vertices.add(SCALE)
normal.copyCoordinatesTo(normals)
texturePoints[j].copyCoordinatesTo(texCoords)
}
for (j in 1..face.size - 2) {
triangles.add(copiedFace[0])
triangles.add(copiedFace[j])
triangles.add(copiedFace[j + 1])
}
}
glFrontFace(GL_CW)
glVertexPointer(4, GL_FLOAT, 0, vertices.toFloatArray().toCValues().ptr)
glTexCoordPointer(2, GL_FLOAT, 0, texCoords.toFloatArray().toCValues().ptr)
glNormalPointer(GL_FLOAT, 0, normals.toFloatArray().toCValues().ptr)
glDrawElements(GL_TRIANGLES, triangles.size, GL_UNSIGNED_BYTE, triangles.toByteArray().toCValues().ptr)
glPopMatrix()
}
private class Vector2(val x: Float, val y: Float) {
val length by lazy { sqrtf(x * x + y * y) }
fun normalized(): Vector2 {
val len = length
return Vector2(x / len, y / len)
}
fun copyCoordinatesTo(arr: MutableList<Float>) {
arr.add(x)
arr.add(y)
}
operator fun minus(other: Vector2) = Vector2(x - other.x, y - other.y)
operator fun plus(other: Vector2) = Vector2(x + other.x, y + other.y)
operator fun times(other: Float) = Vector2(x * other, y * other)
operator fun div(other: Float) = Vector2(x / other, y / other)
companion object {
val Zero = Vector2(0.0f, 0.0f)
}
}
private class Vector3(val x: Float, val y: Float, val z: Float) {
val length by lazy { sqrtf(x * x + y * y + z * z) }
fun crossProduct(other: Vector3): Vector3 =
Vector3(y * other.z - z * other.y, z * other.x - x * other.z, x * other.y - y * other.x)
fun normalized(): Vector3 {
val len = length
return Vector3(x / len, y / len, z / len)
}
fun copyCoordinatesTo(arr: MutableList<Float>) {
arr.add(x)
arr.add(y)
arr.add(z)
}
operator fun minus(other: Vector3) = Vector3(x - other.x, y - other.y, z - other.z)
operator fun plus(other: Vector3) = Vector3(x + other.x, y + other.y, z + other.z)
}
private const val Zero = 0.0f
private const val DodeA = 0.93417235896f // (Sqrt(5) + 1) / (2 * Sqrt(3))
private const val DodeB = 0.35682208977f // (Sqrt(5) - 1) / (2 * Sqrt(3))
private const val DodeC = 0.57735026919f // 1 / Sqrt(3)
private const val IcosA = 0.52573111212f // Sqrt(5 - Sqrt(5)) / Sqrt(10)
private const val IcosB = 0.85065080835f // Sqrt(5 + Sqrt(5)) / Sqrt(10)
private enum class RegularPolyhedra(val vertices: Array<Vector3>, val faces: Array<ByteArray>) {
Dodecahedron(
arrayOf(
Vector3(-DodeA, Zero, DodeB), Vector3(-DodeA, Zero, -DodeB), Vector3(DodeA, Zero, -DodeB),
Vector3(DodeA, Zero, DodeB), Vector3(DodeB, -DodeA, Zero), Vector3(-DodeB, -DodeA, Zero),
Vector3(-DodeB, DodeA, Zero), Vector3(DodeB, DodeA, Zero), Vector3(Zero, DodeB, -DodeA),
Vector3(Zero, -DodeB, -DodeA), Vector3(Zero, -DodeB, DodeA), Vector3(Zero, DodeB, DodeA),
Vector3(-DodeC, -DodeC, DodeC), Vector3(-DodeC, -DodeC, -DodeC), Vector3(DodeC, -DodeC, -DodeC),
Vector3(DodeC, -DodeC, DodeC), Vector3(-DodeC, DodeC, DodeC), Vector3(-DodeC, DodeC, -DodeC),
Vector3(DodeC, DodeC, -DodeC), Vector3(DodeC, DodeC, DodeC)
),
arrayOf(
byteArrayOf(0, 12, 10, 11, 16), byteArrayOf(1, 17, 8, 9, 13), byteArrayOf(2, 14, 9, 8, 18),
byteArrayOf(3, 19, 11, 10, 15), byteArrayOf(4, 14, 2, 3, 15), byteArrayOf(5, 12, 0, 1, 13),
byteArrayOf(6, 17, 1, 0, 16), byteArrayOf(7, 19, 3, 2, 18), byteArrayOf(8, 17, 6, 7, 18),
byteArrayOf(9, 14, 4, 5, 13), byteArrayOf(10, 12, 5, 4, 15), byteArrayOf(11, 19, 7, 6, 16)
)),
Icosahedron(
arrayOf(
Vector3(-IcosA, Zero, IcosB), Vector3(IcosA, Zero, IcosB), Vector3(-IcosA, Zero, -IcosB),
Vector3(IcosA, Zero, -IcosB), Vector3(Zero, IcosB, IcosA), Vector3(Zero, IcosB, -IcosA),
Vector3(Zero, -IcosB, IcosA), Vector3(Zero, -IcosB, -IcosA), Vector3(IcosB, IcosA, Zero),
Vector3(-IcosB, IcosA, Zero), Vector3(IcosB, -IcosA, Zero), Vector3(-IcosB, -IcosA, Zero)
),
arrayOf(
byteArrayOf(1, 4, 0), byteArrayOf(4, 9, 0), byteArrayOf(4, 5, 9), byteArrayOf(8, 5, 4),
byteArrayOf(1, 8, 4), byteArrayOf(1, 10, 8), byteArrayOf(10, 3, 8), byteArrayOf(8, 3, 5),
byteArrayOf(3, 2, 5), byteArrayOf(3, 7, 2), byteArrayOf(3, 10, 7), byteArrayOf(10, 6, 7),
byteArrayOf(6, 11, 7), byteArrayOf(6, 0, 11), byteArrayOf(6, 1, 0), byteArrayOf(10, 1, 6),
byteArrayOf(11, 0, 9), byteArrayOf(2, 11, 9), byteArrayOf(5, 2, 9), byteArrayOf(11, 2, 7)
)
);
val verticesPerFace get() = faces[0].size
}
@@ -0,0 +1,25 @@
kotlin {
// there is no Android Native HMPP shortcut preset, so need to configure targets and common source sets manually
val androidNativeMain by sourceSets.creating { dependsOn(sourceSets["commonMain"]) }
val androidNativeTest by sourceSets.creating { dependsOn(sourceSets["commonTest"]) }
androidNativeX64 {
with(compilations["main"].defaultSourceSet) {
dependsOn(androidNativeMain)
kotlin.srcDir("src/main")
}
with(compilations["test"].defaultSourceSet) {
dependsOn(androidNativeTest)
kotlin.srcDir("src/test")
}
}
androidNativeArm64 {
compilations["main"].defaultSourceSet.dependsOn(androidNativeMain)
compilations["test"].defaultSourceSet.dependsOn(androidNativeTest)
}
}
// project-specific settings go under this line
@@ -0,0 +1,25 @@
kotlin {
// there is no Linux HMPP shortcut preset, so need to configure targets and common source sets manually
val linuxMain by sourceSets.creating { dependsOn(sourceSets["commonMain"]) }
val linuxTest by sourceSets.creating { dependsOn(sourceSets["commonTest"]) }
linuxX64 {
with(compilations["main"].defaultSourceSet) {
dependsOn(linuxMain)
kotlin.srcDir("src/main")
}
with(compilations["test"].defaultSourceSet) {
dependsOn(linuxTest)
kotlin.srcDir("src/test")
}
}
linuxArm64 {
compilations["main"].defaultSourceSet.dependsOn(linuxMain)
compilations["test"].defaultSourceSet.dependsOn(linuxTest)
}
}
// project-specific settings go under this line