diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml index 43edcc2..7ed1494 100644 --- a/.idea/modules/kudens_test.iml +++ b/.idea/modules/kudens_test.iml @@ -1,8 +1,9 @@ - + + $MODULE_DIR$/../../build/kotlinjs/kudens.js \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml index 43edcc2..7ed1494 100644 --- a/.idea/modules/kudens_test.iml +++ b/.idea/modules/kudens_test.iml @@ -1,8 +1,9 @@ - + + $MODULE_DIR$/../../build/kotlinjs/kudens.js \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7ae9969..e7225a0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'perses.games' -version '1.1.6-SNAPSHOT' +version '1.1.7-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'idea' @@ -20,7 +20,7 @@ } buildscript { - ext.kotlin_version = '1.2.21' + ext.kotlin_version = '1.2.30' repositories { maven { url "http://nexus.astraeus.nl/nexus/content/groups/public" diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml index 43edcc2..7ed1494 100644 --- a/.idea/modules/kudens_test.iml +++ b/.idea/modules/kudens_test.iml @@ -1,8 +1,9 @@ - + + $MODULE_DIR$/../../build/kotlinjs/kudens.js \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7ae9969..e7225a0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'perses.games' -version '1.1.6-SNAPSHOT' +version '1.1.7-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'idea' @@ -20,7 +20,7 @@ } buildscript { - ext.kotlin_version = '1.2.21' + ext.kotlin_version = '1.2.30' repositories { maven { url "http://nexus.astraeus.nl/nexus/content/groups/public" diff --git a/src/main/kotlin/games/perses/color/Color.kt b/src/main/kotlin/games/perses/color/Color.kt index 7f235b0..31b540f 100644 --- a/src/main/kotlin/games/perses/color/Color.kt +++ b/src/main/kotlin/games/perses/color/Color.kt @@ -10,107 +10,107 @@ object Color { - /** - * Converts an HSL color value to RGB. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes h, s, and l are contained in the set [0, 1] and - * returns r, g, and b in the set [0, 255]. + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. - * @param h The hue - * * - * @param s The saturation - * * - * @param l The lightness - * * - * @return int array, the RGB representation - */ - fun hslToRgb(h: Float, s: Float, l: Float): IntArray { - val r: Float - val g: Float - val b: Float + * @param h The hue + * * + * @param s The saturation + * * + * @param l The lightness + * * + * @return int array, the RGB representation + */ + fun hslToRgb(h: Float, s: Float, l: Float): IntArray { + val r: Float + val g: Float + val b: Float - if (s == 0f) { - b = l - g = b - r = g // achromatic - } else { - val q = if (l < 0.5f) l * (1 + s) else l + s - l * s - val p = 2 * l - q - r = hueToRgb(p, q, h + 1f / 3f) - g = hueToRgb(p, q, h) - b = hueToRgb(p, q, h - 1f / 3f) - } - val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) + if (s == 0f) { + b = l + g = b + r = g // achromatic + } else { + val q = if (l < 0.5f) l * (1 + s) else l + s - l * s + val p = 2 * l - q + r = hueToRgb(p, q, h + 1f / 3f) + g = hueToRgb(p, q, h) + b = hueToRgb(p, q, h - 1f / 3f) + } + val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) - return rgb + return rgb + } + + /** Helper method that converts hue to rgb */ + fun hueToRgb(p: Float, q: Float, t: Float): Float { + var lt = t + if (lt < 0f) { + lt += 1f + } + if (lt > 1f) { + lt -= 1f + } + if (lt < 1f / 6f) { + return p + (q - p) * 6f * lt + } + if (lt < 1f / 2f) { + return q + } + if (lt < 2f / 3f) { + return p + (q - p) * (2f / 3f - lt) * 6f + } + return p + } + + /** + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes pR, pG, and bpBare contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + + * @param pR The red color value + * * + * @param pG The green color value + * * + * @param pB The blue color value + * * + * @return float array, the HSL representation + */ + fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { + val r = pR / 255f + val g = pG / 255f + val b = pB / 255f + + val max = if (r > g && r > b) r else if (g > b) g else b + val min = if (r < g && r < b) r else if (g < b) g else b + + var h: Float + val s: Float + val l: Float + l = (max + min) / 2.0f + + if (max == min) { + s = 0.0f + h = s + } else { + val d = max - min + s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) + + if (r > g && r > b) + h = (g - b) / d + (if (g < b) 6.0f else 0.0f) + else if (g > b) + h = (b - r) / d + 2.0f + else + h = (r - g) / d + 4.0f + + h /= 6.0f } - /** Helper method that converts hue to rgb */ - fun hueToRgb(p: Float, q: Float, t: Float): Float { - var lt = t - if (lt < 0f) { - lt += 1f - } - if (lt > 1f) { - lt -= 1f - } - if (lt < 1f / 6f) { - return p + (q - p) * 6f * lt - } - if (lt < 1f / 2f) { - return q - } - if (lt < 2f / 3f) { - return p + (q - p) * (2f / 3f - lt) * 6f - } - return p - } - - /** - * Converts an RGB color value to HSL. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes pR, pG, and bpBare contained in the set [0, 255] and - * returns h, s, and l in the set [0, 1]. - - * @param pR The red color value - * * - * @param pG The green color value - * * - * @param pB The blue color value - * * - * @return float array, the HSL representation - */ - fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { - val r = pR / 255f - val g = pG / 255f - val b = pB / 255f - - val max = if (r > g && r > b) r else if (g > b) g else b - val min = if (r < g && r < b) r else if (g < b) g else b - - var h: Float - val s: Float - val l: Float - l = (max + min) / 2.0f - - if (max == min) { - s = 0.0f - h = s - } else { - val d = max - min - s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) - - if (r > g && r > b) - h = (g - b) / d + (if (g < b) 6.0f else 0.0f) - else if (g > b) - h = (b - r) / d + 2.0f - else - h = (r - g) / d + 4.0f - - h /= 6.0f - } - - val hsl = floatArrayOf(h, s, l) - return hsl - } + val hsl = floatArrayOf(h, s, l) + return hsl + } } \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml index 43edcc2..7ed1494 100644 --- a/.idea/modules/kudens_test.iml +++ b/.idea/modules/kudens_test.iml @@ -1,8 +1,9 @@ - + + $MODULE_DIR$/../../build/kotlinjs/kudens.js \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7ae9969..e7225a0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'perses.games' -version '1.1.6-SNAPSHOT' +version '1.1.7-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'idea' @@ -20,7 +20,7 @@ } buildscript { - ext.kotlin_version = '1.2.21' + ext.kotlin_version = '1.2.30' repositories { maven { url "http://nexus.astraeus.nl/nexus/content/groups/public" diff --git a/src/main/kotlin/games/perses/color/Color.kt b/src/main/kotlin/games/perses/color/Color.kt index 7f235b0..31b540f 100644 --- a/src/main/kotlin/games/perses/color/Color.kt +++ b/src/main/kotlin/games/perses/color/Color.kt @@ -10,107 +10,107 @@ object Color { - /** - * Converts an HSL color value to RGB. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes h, s, and l are contained in the set [0, 1] and - * returns r, g, and b in the set [0, 255]. + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. - * @param h The hue - * * - * @param s The saturation - * * - * @param l The lightness - * * - * @return int array, the RGB representation - */ - fun hslToRgb(h: Float, s: Float, l: Float): IntArray { - val r: Float - val g: Float - val b: Float + * @param h The hue + * * + * @param s The saturation + * * + * @param l The lightness + * * + * @return int array, the RGB representation + */ + fun hslToRgb(h: Float, s: Float, l: Float): IntArray { + val r: Float + val g: Float + val b: Float - if (s == 0f) { - b = l - g = b - r = g // achromatic - } else { - val q = if (l < 0.5f) l * (1 + s) else l + s - l * s - val p = 2 * l - q - r = hueToRgb(p, q, h + 1f / 3f) - g = hueToRgb(p, q, h) - b = hueToRgb(p, q, h - 1f / 3f) - } - val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) + if (s == 0f) { + b = l + g = b + r = g // achromatic + } else { + val q = if (l < 0.5f) l * (1 + s) else l + s - l * s + val p = 2 * l - q + r = hueToRgb(p, q, h + 1f / 3f) + g = hueToRgb(p, q, h) + b = hueToRgb(p, q, h - 1f / 3f) + } + val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) - return rgb + return rgb + } + + /** Helper method that converts hue to rgb */ + fun hueToRgb(p: Float, q: Float, t: Float): Float { + var lt = t + if (lt < 0f) { + lt += 1f + } + if (lt > 1f) { + lt -= 1f + } + if (lt < 1f / 6f) { + return p + (q - p) * 6f * lt + } + if (lt < 1f / 2f) { + return q + } + if (lt < 2f / 3f) { + return p + (q - p) * (2f / 3f - lt) * 6f + } + return p + } + + /** + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes pR, pG, and bpBare contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + + * @param pR The red color value + * * + * @param pG The green color value + * * + * @param pB The blue color value + * * + * @return float array, the HSL representation + */ + fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { + val r = pR / 255f + val g = pG / 255f + val b = pB / 255f + + val max = if (r > g && r > b) r else if (g > b) g else b + val min = if (r < g && r < b) r else if (g < b) g else b + + var h: Float + val s: Float + val l: Float + l = (max + min) / 2.0f + + if (max == min) { + s = 0.0f + h = s + } else { + val d = max - min + s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) + + if (r > g && r > b) + h = (g - b) / d + (if (g < b) 6.0f else 0.0f) + else if (g > b) + h = (b - r) / d + 2.0f + else + h = (r - g) / d + 4.0f + + h /= 6.0f } - /** Helper method that converts hue to rgb */ - fun hueToRgb(p: Float, q: Float, t: Float): Float { - var lt = t - if (lt < 0f) { - lt += 1f - } - if (lt > 1f) { - lt -= 1f - } - if (lt < 1f / 6f) { - return p + (q - p) * 6f * lt - } - if (lt < 1f / 2f) { - return q - } - if (lt < 2f / 3f) { - return p + (q - p) * (2f / 3f - lt) * 6f - } - return p - } - - /** - * Converts an RGB color value to HSL. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes pR, pG, and bpBare contained in the set [0, 255] and - * returns h, s, and l in the set [0, 1]. - - * @param pR The red color value - * * - * @param pG The green color value - * * - * @param pB The blue color value - * * - * @return float array, the HSL representation - */ - fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { - val r = pR / 255f - val g = pG / 255f - val b = pB / 255f - - val max = if (r > g && r > b) r else if (g > b) g else b - val min = if (r < g && r < b) r else if (g < b) g else b - - var h: Float - val s: Float - val l: Float - l = (max + min) / 2.0f - - if (max == min) { - s = 0.0f - h = s - } else { - val d = max - min - s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) - - if (r > g && r > b) - h = (g - b) / d + (if (g < b) 6.0f else 0.0f) - else if (g > b) - h = (b - r) / d + 2.0f - else - h = (r - g) / d + 4.0f - - h /= 6.0f - } - - val hsl = floatArrayOf(h, s, l) - return hsl - } + val hsl = floatArrayOf(h, s, l) + return hsl + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/game/Game.kt b/src/main/kotlin/games/perses/game/Game.kt index 0961316..1becee5 100644 --- a/src/main/kotlin/games/perses/game/Game.kt +++ b/src/main/kotlin/games/perses/game/Game.kt @@ -14,210 +14,210 @@ */ enum class DrawMode { - LINEAR, - NEAREST + LINEAR, + NEAREST } class HTMLElements { - var container: HTMLElement - var webgl: WebGLRenderingContext - var canvas2d: CanvasRenderingContext2D + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D - init { - container = document.createElement("div") as HTMLElement + init { + container = document.createElement("div") as HTMLElement - val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement - val canvas = document.createElement("canvas") as HTMLCanvasElement + val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + val canvas = document.createElement("canvas") as HTMLCanvasElement - container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") - webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" ) - canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" ) + container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;") - document.body!!.appendChild(container) - container.appendChild(webGlCanvas) - container.appendChild(canvas) + document.body!!.appendChild(container) + container.appendChild(webGlCanvas) + container.appendChild(canvas) - val canvas2dcanvas = canvas.getContext("2d") + val canvas2dcanvas = canvas.getContext("2d") - var webglcanvas = webGlCanvas.getContext("webgl") - if (webglcanvas == null) { - console.log("webgl context not found, trying experimental-webgl.") - webglcanvas = webGlCanvas.getContext("experimental-webgl") - } - - if (webglcanvas != null) { - webgl = webglcanvas as WebGLRenderingContext - } else { - console.log("webgl?", webglcanvas) - window.alert("Your browser doesn't seem to support webgl!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } - - if (canvas2dcanvas != null) { - canvas2d = canvas2dcanvas as CanvasRenderingContext2D - } else { - console.log("canvas2d?", canvas2dcanvas) - window.alert("Your browser doesn't seem to support 2d canvas!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } + var webglcanvas = webGlCanvas.getContext("webgl") + if (webglcanvas == null) { + console.log("webgl context not found, trying experimental-webgl.") + webglcanvas = webGlCanvas.getContext("experimental-webgl") } + + if (webglcanvas != null) { + webgl = webglcanvas as WebGLRenderingContext + } else { + console.log("webgl?", webglcanvas) + window.alert("Your browser doesn't seem to support webgl!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + + if (canvas2dcanvas != null) { + canvas2d = canvas2dcanvas as CanvasRenderingContext2D + } else { + console.log("canvas2d?", canvas2dcanvas) + window.alert("Your browser doesn't seem to support 2d canvas!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + } } object Game { - var started = false - val view: View = View() - val html: HTMLElements by lazy { HTMLElements() } - var currentScreen: Screen = DefaultScreen() - var start = Date().getTime() - var currentTime = start - var currentDelta = 0f - var pause: Boolean = false - var clearScreenEveryFrame = true + var started = false + val view: View = View() + val html: HTMLElements by lazy { HTMLElements() } + var currentScreen: Screen = DefaultScreen() + var start = Date().getTime() + var currentTime = start + var currentDelta = 0f + var pause: Boolean = false + var clearScreenEveryFrame = true - var clearRed = 0f - var clearGreen = 0f - var clearBlue = 0f - var clearAlpha = 1f + var clearRed = 0f + var clearGreen = 0f + var clearBlue = 0f + var clearAlpha = 1f - var fps = 0 - var fpsCount = 0 - var fpsCountTime = 0f + var fps = 0 + var fpsCount = 0 + var fpsCountTime = 0f - var borderLeft = 0 - var borderTop = 0 + var borderLeft = 0 + var borderTop = 0 - var focus = true + var focus = true - init { - window.onfocus = { - //println("GOT FOCUS!") + init { + window.onfocus = { + //println("GOT FOCUS!") - focus = true - "" - } - window.onblur = { - //println("LOST FOCUS!") + focus = true + "" + } + window.onblur = { + //println("LOST FOCUS!") - focus = false - "" - } - + focus = false + "" } - fun gl() = html.webgl + } - fun resize() { - val canvas = gl().canvas + fun gl() = html.webgl - // Check if the canvas is not the same size. - val windowWidth = window.innerWidth.toInt() - val windowHeight = window.innerHeight.toInt() + fun resize() { + val canvas = gl().canvas - if (view.lastWindowWidth != windowWidth || - view.lastWindowHeight != windowHeight) { - view.lastWindowWidth = windowWidth - view.lastWindowHeight = windowHeight - view.windowWidth = windowWidth - view.windowHeight = windowHeight + // Check if the canvas is not the same size. + val windowWidth = window.innerWidth.toInt() + val windowHeight = window.innerHeight.toInt() - view.updateView() + if (view.lastWindowWidth != windowWidth || + view.lastWindowHeight != windowHeight) { + view.lastWindowWidth = windowWidth + view.lastWindowHeight = windowHeight + view.windowWidth = windowWidth + view.windowHeight = windowHeight - val textCanvas = html.canvas2d.canvas + view.updateView() - // Make the canvas the same size - canvas.width = view.width.toInt() - canvas.height = view.height.toInt() + val textCanvas = html.canvas2d.canvas - textCanvas.width = view.width.toInt() - textCanvas.height = view.height.toInt() + // Make the canvas the same size + canvas.width = view.width.toInt() + canvas.height = view.height.toInt() - gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) + textCanvas.width = view.width.toInt() + textCanvas.height = view.height.toInt() - borderLeft = (windowWidth - view.windowWidth) / 2 - borderTop = (windowHeight - view.windowHeight) / 2 + gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) - canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) - textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) + borderLeft = (windowWidth - view.windowWidth) / 2 + borderTop = (windowHeight - view.windowHeight) / 2 + + canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + } + } + + fun start(startScreen: Screen) { + if (started) { + throw IllegalStateException("You can only start a game once!") + } + + setScreen(startScreen) + + // start game loop + started = true + gameLoop() + } + + fun setScreen(screen: Screen) { + currentScreen.unloadResources() + + currentScreen = screen + + screen.loadResources() + } + + fun setClearColor(r: Float, g: Float, b: Float, a: Float) { + clearRed = r + clearGreen = g + clearBlue = b + clearAlpha = a + } + + fun gameLoop() { + try { + if (!Textures.ready()) { + gl().clearColor(1f, 1f, 1f, 1f) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } else { + resize() + + if (!pause) { + html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); + + if (clearScreenEveryFrame) { + gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } + + gl().enable(WebGLRenderingContext.BLEND) + gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); + + val time = Date().getTime() + currentDelta = ((time - currentTime) / 1000f).toFloat() + currentTime = time + + val timeInSeconds = (currentTime - start) / 1000f + + fpsCountTime += currentDelta + fpsCount++ + while (fpsCountTime > 1f) { + fps = fpsCount + fpsCountTime -= 1f + fpsCount = 0 + } + + if (focus) { + currentScreen.update(timeInSeconds.toFloat(), currentDelta) + } + + currentScreen.render() } + } + } catch (e: Exception) { + println("Some error...") + console.log(e) } - fun start(startScreen: Screen) { - if (started) { - throw IllegalStateException("You can only start a game once!") - } - - setScreen(startScreen) - - // start game loop - started = true - gameLoop() + window.requestAnimationFrame { + gameLoop() } - - fun setScreen(screen: Screen) { - currentScreen.unloadResources() - - currentScreen = screen - - screen.loadResources() - } - - fun setClearColor(r: Float, g: Float, b: Float, a: Float) { - clearRed = r - clearGreen = g - clearBlue = b - clearAlpha = a - } - - fun gameLoop() { - try { - if (!Textures.ready()) { - gl().clearColor(1f, 1f, 1f, 1f) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } else { - resize() - - if (!pause) { - html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); - - if (clearScreenEveryFrame) { - gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } - - gl().enable(WebGLRenderingContext.BLEND) - gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); - - val time = Date().getTime() - currentDelta = ((time - currentTime) / 1000f).toFloat() - currentTime = time - - val timeInSeconds = (currentTime - start) / 1000f - - fpsCountTime += currentDelta - fpsCount++ - while (fpsCountTime > 1f) { - fps = fpsCount - fpsCountTime -= 1f - fpsCount = 0 - } - - if (focus) { - currentScreen.update(timeInSeconds.toFloat(), currentDelta) - } - - currentScreen.render() - } - } - } catch(e: Exception) { - println("Some error...") - console.log(e) - } - - window.requestAnimationFrame { - gameLoop() - } - } + } } diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml index 43edcc2..7ed1494 100644 --- a/.idea/modules/kudens_test.iml +++ b/.idea/modules/kudens_test.iml @@ -1,8 +1,9 @@ - + + $MODULE_DIR$/../../build/kotlinjs/kudens.js \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7ae9969..e7225a0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'perses.games' -version '1.1.6-SNAPSHOT' +version '1.1.7-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'idea' @@ -20,7 +20,7 @@ } buildscript { - ext.kotlin_version = '1.2.21' + ext.kotlin_version = '1.2.30' repositories { maven { url "http://nexus.astraeus.nl/nexus/content/groups/public" diff --git a/src/main/kotlin/games/perses/color/Color.kt b/src/main/kotlin/games/perses/color/Color.kt index 7f235b0..31b540f 100644 --- a/src/main/kotlin/games/perses/color/Color.kt +++ b/src/main/kotlin/games/perses/color/Color.kt @@ -10,107 +10,107 @@ object Color { - /** - * Converts an HSL color value to RGB. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes h, s, and l are contained in the set [0, 1] and - * returns r, g, and b in the set [0, 255]. + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. - * @param h The hue - * * - * @param s The saturation - * * - * @param l The lightness - * * - * @return int array, the RGB representation - */ - fun hslToRgb(h: Float, s: Float, l: Float): IntArray { - val r: Float - val g: Float - val b: Float + * @param h The hue + * * + * @param s The saturation + * * + * @param l The lightness + * * + * @return int array, the RGB representation + */ + fun hslToRgb(h: Float, s: Float, l: Float): IntArray { + val r: Float + val g: Float + val b: Float - if (s == 0f) { - b = l - g = b - r = g // achromatic - } else { - val q = if (l < 0.5f) l * (1 + s) else l + s - l * s - val p = 2 * l - q - r = hueToRgb(p, q, h + 1f / 3f) - g = hueToRgb(p, q, h) - b = hueToRgb(p, q, h - 1f / 3f) - } - val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) + if (s == 0f) { + b = l + g = b + r = g // achromatic + } else { + val q = if (l < 0.5f) l * (1 + s) else l + s - l * s + val p = 2 * l - q + r = hueToRgb(p, q, h + 1f / 3f) + g = hueToRgb(p, q, h) + b = hueToRgb(p, q, h - 1f / 3f) + } + val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) - return rgb + return rgb + } + + /** Helper method that converts hue to rgb */ + fun hueToRgb(p: Float, q: Float, t: Float): Float { + var lt = t + if (lt < 0f) { + lt += 1f + } + if (lt > 1f) { + lt -= 1f + } + if (lt < 1f / 6f) { + return p + (q - p) * 6f * lt + } + if (lt < 1f / 2f) { + return q + } + if (lt < 2f / 3f) { + return p + (q - p) * (2f / 3f - lt) * 6f + } + return p + } + + /** + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes pR, pG, and bpBare contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + + * @param pR The red color value + * * + * @param pG The green color value + * * + * @param pB The blue color value + * * + * @return float array, the HSL representation + */ + fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { + val r = pR / 255f + val g = pG / 255f + val b = pB / 255f + + val max = if (r > g && r > b) r else if (g > b) g else b + val min = if (r < g && r < b) r else if (g < b) g else b + + var h: Float + val s: Float + val l: Float + l = (max + min) / 2.0f + + if (max == min) { + s = 0.0f + h = s + } else { + val d = max - min + s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) + + if (r > g && r > b) + h = (g - b) / d + (if (g < b) 6.0f else 0.0f) + else if (g > b) + h = (b - r) / d + 2.0f + else + h = (r - g) / d + 4.0f + + h /= 6.0f } - /** Helper method that converts hue to rgb */ - fun hueToRgb(p: Float, q: Float, t: Float): Float { - var lt = t - if (lt < 0f) { - lt += 1f - } - if (lt > 1f) { - lt -= 1f - } - if (lt < 1f / 6f) { - return p + (q - p) * 6f * lt - } - if (lt < 1f / 2f) { - return q - } - if (lt < 2f / 3f) { - return p + (q - p) * (2f / 3f - lt) * 6f - } - return p - } - - /** - * Converts an RGB color value to HSL. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes pR, pG, and bpBare contained in the set [0, 255] and - * returns h, s, and l in the set [0, 1]. - - * @param pR The red color value - * * - * @param pG The green color value - * * - * @param pB The blue color value - * * - * @return float array, the HSL representation - */ - fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { - val r = pR / 255f - val g = pG / 255f - val b = pB / 255f - - val max = if (r > g && r > b) r else if (g > b) g else b - val min = if (r < g && r < b) r else if (g < b) g else b - - var h: Float - val s: Float - val l: Float - l = (max + min) / 2.0f - - if (max == min) { - s = 0.0f - h = s - } else { - val d = max - min - s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) - - if (r > g && r > b) - h = (g - b) / d + (if (g < b) 6.0f else 0.0f) - else if (g > b) - h = (b - r) / d + 2.0f - else - h = (r - g) / d + 4.0f - - h /= 6.0f - } - - val hsl = floatArrayOf(h, s, l) - return hsl - } + val hsl = floatArrayOf(h, s, l) + return hsl + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/game/Game.kt b/src/main/kotlin/games/perses/game/Game.kt index 0961316..1becee5 100644 --- a/src/main/kotlin/games/perses/game/Game.kt +++ b/src/main/kotlin/games/perses/game/Game.kt @@ -14,210 +14,210 @@ */ enum class DrawMode { - LINEAR, - NEAREST + LINEAR, + NEAREST } class HTMLElements { - var container: HTMLElement - var webgl: WebGLRenderingContext - var canvas2d: CanvasRenderingContext2D + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D - init { - container = document.createElement("div") as HTMLElement + init { + container = document.createElement("div") as HTMLElement - val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement - val canvas = document.createElement("canvas") as HTMLCanvasElement + val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + val canvas = document.createElement("canvas") as HTMLCanvasElement - container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") - webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" ) - canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" ) + container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;") - document.body!!.appendChild(container) - container.appendChild(webGlCanvas) - container.appendChild(canvas) + document.body!!.appendChild(container) + container.appendChild(webGlCanvas) + container.appendChild(canvas) - val canvas2dcanvas = canvas.getContext("2d") + val canvas2dcanvas = canvas.getContext("2d") - var webglcanvas = webGlCanvas.getContext("webgl") - if (webglcanvas == null) { - console.log("webgl context not found, trying experimental-webgl.") - webglcanvas = webGlCanvas.getContext("experimental-webgl") - } - - if (webglcanvas != null) { - webgl = webglcanvas as WebGLRenderingContext - } else { - console.log("webgl?", webglcanvas) - window.alert("Your browser doesn't seem to support webgl!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } - - if (canvas2dcanvas != null) { - canvas2d = canvas2dcanvas as CanvasRenderingContext2D - } else { - console.log("canvas2d?", canvas2dcanvas) - window.alert("Your browser doesn't seem to support 2d canvas!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } + var webglcanvas = webGlCanvas.getContext("webgl") + if (webglcanvas == null) { + console.log("webgl context not found, trying experimental-webgl.") + webglcanvas = webGlCanvas.getContext("experimental-webgl") } + + if (webglcanvas != null) { + webgl = webglcanvas as WebGLRenderingContext + } else { + console.log("webgl?", webglcanvas) + window.alert("Your browser doesn't seem to support webgl!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + + if (canvas2dcanvas != null) { + canvas2d = canvas2dcanvas as CanvasRenderingContext2D + } else { + console.log("canvas2d?", canvas2dcanvas) + window.alert("Your browser doesn't seem to support 2d canvas!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + } } object Game { - var started = false - val view: View = View() - val html: HTMLElements by lazy { HTMLElements() } - var currentScreen: Screen = DefaultScreen() - var start = Date().getTime() - var currentTime = start - var currentDelta = 0f - var pause: Boolean = false - var clearScreenEveryFrame = true + var started = false + val view: View = View() + val html: HTMLElements by lazy { HTMLElements() } + var currentScreen: Screen = DefaultScreen() + var start = Date().getTime() + var currentTime = start + var currentDelta = 0f + var pause: Boolean = false + var clearScreenEveryFrame = true - var clearRed = 0f - var clearGreen = 0f - var clearBlue = 0f - var clearAlpha = 1f + var clearRed = 0f + var clearGreen = 0f + var clearBlue = 0f + var clearAlpha = 1f - var fps = 0 - var fpsCount = 0 - var fpsCountTime = 0f + var fps = 0 + var fpsCount = 0 + var fpsCountTime = 0f - var borderLeft = 0 - var borderTop = 0 + var borderLeft = 0 + var borderTop = 0 - var focus = true + var focus = true - init { - window.onfocus = { - //println("GOT FOCUS!") + init { + window.onfocus = { + //println("GOT FOCUS!") - focus = true - "" - } - window.onblur = { - //println("LOST FOCUS!") + focus = true + "" + } + window.onblur = { + //println("LOST FOCUS!") - focus = false - "" - } - + focus = false + "" } - fun gl() = html.webgl + } - fun resize() { - val canvas = gl().canvas + fun gl() = html.webgl - // Check if the canvas is not the same size. - val windowWidth = window.innerWidth.toInt() - val windowHeight = window.innerHeight.toInt() + fun resize() { + val canvas = gl().canvas - if (view.lastWindowWidth != windowWidth || - view.lastWindowHeight != windowHeight) { - view.lastWindowWidth = windowWidth - view.lastWindowHeight = windowHeight - view.windowWidth = windowWidth - view.windowHeight = windowHeight + // Check if the canvas is not the same size. + val windowWidth = window.innerWidth.toInt() + val windowHeight = window.innerHeight.toInt() - view.updateView() + if (view.lastWindowWidth != windowWidth || + view.lastWindowHeight != windowHeight) { + view.lastWindowWidth = windowWidth + view.lastWindowHeight = windowHeight + view.windowWidth = windowWidth + view.windowHeight = windowHeight - val textCanvas = html.canvas2d.canvas + view.updateView() - // Make the canvas the same size - canvas.width = view.width.toInt() - canvas.height = view.height.toInt() + val textCanvas = html.canvas2d.canvas - textCanvas.width = view.width.toInt() - textCanvas.height = view.height.toInt() + // Make the canvas the same size + canvas.width = view.width.toInt() + canvas.height = view.height.toInt() - gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) + textCanvas.width = view.width.toInt() + textCanvas.height = view.height.toInt() - borderLeft = (windowWidth - view.windowWidth) / 2 - borderTop = (windowHeight - view.windowHeight) / 2 + gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) - canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) - textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) + borderLeft = (windowWidth - view.windowWidth) / 2 + borderTop = (windowHeight - view.windowHeight) / 2 + + canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + } + } + + fun start(startScreen: Screen) { + if (started) { + throw IllegalStateException("You can only start a game once!") + } + + setScreen(startScreen) + + // start game loop + started = true + gameLoop() + } + + fun setScreen(screen: Screen) { + currentScreen.unloadResources() + + currentScreen = screen + + screen.loadResources() + } + + fun setClearColor(r: Float, g: Float, b: Float, a: Float) { + clearRed = r + clearGreen = g + clearBlue = b + clearAlpha = a + } + + fun gameLoop() { + try { + if (!Textures.ready()) { + gl().clearColor(1f, 1f, 1f, 1f) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } else { + resize() + + if (!pause) { + html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); + + if (clearScreenEveryFrame) { + gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } + + gl().enable(WebGLRenderingContext.BLEND) + gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); + + val time = Date().getTime() + currentDelta = ((time - currentTime) / 1000f).toFloat() + currentTime = time + + val timeInSeconds = (currentTime - start) / 1000f + + fpsCountTime += currentDelta + fpsCount++ + while (fpsCountTime > 1f) { + fps = fpsCount + fpsCountTime -= 1f + fpsCount = 0 + } + + if (focus) { + currentScreen.update(timeInSeconds.toFloat(), currentDelta) + } + + currentScreen.render() } + } + } catch (e: Exception) { + println("Some error...") + console.log(e) } - fun start(startScreen: Screen) { - if (started) { - throw IllegalStateException("You can only start a game once!") - } - - setScreen(startScreen) - - // start game loop - started = true - gameLoop() + window.requestAnimationFrame { + gameLoop() } - - fun setScreen(screen: Screen) { - currentScreen.unloadResources() - - currentScreen = screen - - screen.loadResources() - } - - fun setClearColor(r: Float, g: Float, b: Float, a: Float) { - clearRed = r - clearGreen = g - clearBlue = b - clearAlpha = a - } - - fun gameLoop() { - try { - if (!Textures.ready()) { - gl().clearColor(1f, 1f, 1f, 1f) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } else { - resize() - - if (!pause) { - html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); - - if (clearScreenEveryFrame) { - gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } - - gl().enable(WebGLRenderingContext.BLEND) - gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); - - val time = Date().getTime() - currentDelta = ((time - currentTime) / 1000f).toFloat() - currentTime = time - - val timeInSeconds = (currentTime - start) / 1000f - - fpsCountTime += currentDelta - fpsCount++ - while (fpsCountTime > 1f) { - fps = fpsCount - fpsCountTime -= 1f - fpsCount = 0 - } - - if (focus) { - currentScreen.update(timeInSeconds.toFloat(), currentDelta) - } - - currentScreen.render() - } - } - } catch(e: Exception) { - println("Some error...") - console.log(e) - } - - window.requestAnimationFrame { - gameLoop() - } - } + } } diff --git a/src/main/kotlin/games/perses/game/Screen.kt b/src/main/kotlin/games/perses/game/Screen.kt index 10b6eae..7b381e7 100644 --- a/src/main/kotlin/games/perses/game/Screen.kt +++ b/src/main/kotlin/games/perses/game/Screen.kt @@ -8,31 +8,31 @@ abstract class Screen { - open fun loadResources() {} + open fun loadResources() {} - @Deprecated( + @Deprecated( message = "replace with unloadResources", replaceWith = ReplaceWith("unloadResources()") - ) - open fun closeResources() { - unloadResources() - } + ) + open fun closeResources() { + unloadResources() + } - open fun unloadResources() {} + open fun unloadResources() {} - abstract fun update(time: Float, delta: Float) + abstract fun update(time: Float, delta: Float) - abstract fun render() + abstract fun render() } -class DefaultScreen: Screen() { - override fun update(time: Float, delta: Float) { - } +class DefaultScreen : Screen() { + override fun update(time: Float, delta: Float) { + } - override fun render() { - // show loading message? - Game.gl().clearColor(1f, 1f, 0f, 1f) - Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } + override fun render() { + // show loading message? + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } } diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml index 43edcc2..7ed1494 100644 --- a/.idea/modules/kudens_test.iml +++ b/.idea/modules/kudens_test.iml @@ -1,8 +1,9 @@ - + + $MODULE_DIR$/../../build/kotlinjs/kudens.js \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7ae9969..e7225a0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'perses.games' -version '1.1.6-SNAPSHOT' +version '1.1.7-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'idea' @@ -20,7 +20,7 @@ } buildscript { - ext.kotlin_version = '1.2.21' + ext.kotlin_version = '1.2.30' repositories { maven { url "http://nexus.astraeus.nl/nexus/content/groups/public" diff --git a/src/main/kotlin/games/perses/color/Color.kt b/src/main/kotlin/games/perses/color/Color.kt index 7f235b0..31b540f 100644 --- a/src/main/kotlin/games/perses/color/Color.kt +++ b/src/main/kotlin/games/perses/color/Color.kt @@ -10,107 +10,107 @@ object Color { - /** - * Converts an HSL color value to RGB. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes h, s, and l are contained in the set [0, 1] and - * returns r, g, and b in the set [0, 255]. + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. - * @param h The hue - * * - * @param s The saturation - * * - * @param l The lightness - * * - * @return int array, the RGB representation - */ - fun hslToRgb(h: Float, s: Float, l: Float): IntArray { - val r: Float - val g: Float - val b: Float + * @param h The hue + * * + * @param s The saturation + * * + * @param l The lightness + * * + * @return int array, the RGB representation + */ + fun hslToRgb(h: Float, s: Float, l: Float): IntArray { + val r: Float + val g: Float + val b: Float - if (s == 0f) { - b = l - g = b - r = g // achromatic - } else { - val q = if (l < 0.5f) l * (1 + s) else l + s - l * s - val p = 2 * l - q - r = hueToRgb(p, q, h + 1f / 3f) - g = hueToRgb(p, q, h) - b = hueToRgb(p, q, h - 1f / 3f) - } - val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) + if (s == 0f) { + b = l + g = b + r = g // achromatic + } else { + val q = if (l < 0.5f) l * (1 + s) else l + s - l * s + val p = 2 * l - q + r = hueToRgb(p, q, h + 1f / 3f) + g = hueToRgb(p, q, h) + b = hueToRgb(p, q, h - 1f / 3f) + } + val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) - return rgb + return rgb + } + + /** Helper method that converts hue to rgb */ + fun hueToRgb(p: Float, q: Float, t: Float): Float { + var lt = t + if (lt < 0f) { + lt += 1f + } + if (lt > 1f) { + lt -= 1f + } + if (lt < 1f / 6f) { + return p + (q - p) * 6f * lt + } + if (lt < 1f / 2f) { + return q + } + if (lt < 2f / 3f) { + return p + (q - p) * (2f / 3f - lt) * 6f + } + return p + } + + /** + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes pR, pG, and bpBare contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + + * @param pR The red color value + * * + * @param pG The green color value + * * + * @param pB The blue color value + * * + * @return float array, the HSL representation + */ + fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { + val r = pR / 255f + val g = pG / 255f + val b = pB / 255f + + val max = if (r > g && r > b) r else if (g > b) g else b + val min = if (r < g && r < b) r else if (g < b) g else b + + var h: Float + val s: Float + val l: Float + l = (max + min) / 2.0f + + if (max == min) { + s = 0.0f + h = s + } else { + val d = max - min + s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) + + if (r > g && r > b) + h = (g - b) / d + (if (g < b) 6.0f else 0.0f) + else if (g > b) + h = (b - r) / d + 2.0f + else + h = (r - g) / d + 4.0f + + h /= 6.0f } - /** Helper method that converts hue to rgb */ - fun hueToRgb(p: Float, q: Float, t: Float): Float { - var lt = t - if (lt < 0f) { - lt += 1f - } - if (lt > 1f) { - lt -= 1f - } - if (lt < 1f / 6f) { - return p + (q - p) * 6f * lt - } - if (lt < 1f / 2f) { - return q - } - if (lt < 2f / 3f) { - return p + (q - p) * (2f / 3f - lt) * 6f - } - return p - } - - /** - * Converts an RGB color value to HSL. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes pR, pG, and bpBare contained in the set [0, 255] and - * returns h, s, and l in the set [0, 1]. - - * @param pR The red color value - * * - * @param pG The green color value - * * - * @param pB The blue color value - * * - * @return float array, the HSL representation - */ - fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { - val r = pR / 255f - val g = pG / 255f - val b = pB / 255f - - val max = if (r > g && r > b) r else if (g > b) g else b - val min = if (r < g && r < b) r else if (g < b) g else b - - var h: Float - val s: Float - val l: Float - l = (max + min) / 2.0f - - if (max == min) { - s = 0.0f - h = s - } else { - val d = max - min - s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) - - if (r > g && r > b) - h = (g - b) / d + (if (g < b) 6.0f else 0.0f) - else if (g > b) - h = (b - r) / d + 2.0f - else - h = (r - g) / d + 4.0f - - h /= 6.0f - } - - val hsl = floatArrayOf(h, s, l) - return hsl - } + val hsl = floatArrayOf(h, s, l) + return hsl + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/game/Game.kt b/src/main/kotlin/games/perses/game/Game.kt index 0961316..1becee5 100644 --- a/src/main/kotlin/games/perses/game/Game.kt +++ b/src/main/kotlin/games/perses/game/Game.kt @@ -14,210 +14,210 @@ */ enum class DrawMode { - LINEAR, - NEAREST + LINEAR, + NEAREST } class HTMLElements { - var container: HTMLElement - var webgl: WebGLRenderingContext - var canvas2d: CanvasRenderingContext2D + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D - init { - container = document.createElement("div") as HTMLElement + init { + container = document.createElement("div") as HTMLElement - val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement - val canvas = document.createElement("canvas") as HTMLCanvasElement + val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + val canvas = document.createElement("canvas") as HTMLCanvasElement - container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") - webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" ) - canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" ) + container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;") - document.body!!.appendChild(container) - container.appendChild(webGlCanvas) - container.appendChild(canvas) + document.body!!.appendChild(container) + container.appendChild(webGlCanvas) + container.appendChild(canvas) - val canvas2dcanvas = canvas.getContext("2d") + val canvas2dcanvas = canvas.getContext("2d") - var webglcanvas = webGlCanvas.getContext("webgl") - if (webglcanvas == null) { - console.log("webgl context not found, trying experimental-webgl.") - webglcanvas = webGlCanvas.getContext("experimental-webgl") - } - - if (webglcanvas != null) { - webgl = webglcanvas as WebGLRenderingContext - } else { - console.log("webgl?", webglcanvas) - window.alert("Your browser doesn't seem to support webgl!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } - - if (canvas2dcanvas != null) { - canvas2d = canvas2dcanvas as CanvasRenderingContext2D - } else { - console.log("canvas2d?", canvas2dcanvas) - window.alert("Your browser doesn't seem to support 2d canvas!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } + var webglcanvas = webGlCanvas.getContext("webgl") + if (webglcanvas == null) { + console.log("webgl context not found, trying experimental-webgl.") + webglcanvas = webGlCanvas.getContext("experimental-webgl") } + + if (webglcanvas != null) { + webgl = webglcanvas as WebGLRenderingContext + } else { + console.log("webgl?", webglcanvas) + window.alert("Your browser doesn't seem to support webgl!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + + if (canvas2dcanvas != null) { + canvas2d = canvas2dcanvas as CanvasRenderingContext2D + } else { + console.log("canvas2d?", canvas2dcanvas) + window.alert("Your browser doesn't seem to support 2d canvas!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + } } object Game { - var started = false - val view: View = View() - val html: HTMLElements by lazy { HTMLElements() } - var currentScreen: Screen = DefaultScreen() - var start = Date().getTime() - var currentTime = start - var currentDelta = 0f - var pause: Boolean = false - var clearScreenEveryFrame = true + var started = false + val view: View = View() + val html: HTMLElements by lazy { HTMLElements() } + var currentScreen: Screen = DefaultScreen() + var start = Date().getTime() + var currentTime = start + var currentDelta = 0f + var pause: Boolean = false + var clearScreenEveryFrame = true - var clearRed = 0f - var clearGreen = 0f - var clearBlue = 0f - var clearAlpha = 1f + var clearRed = 0f + var clearGreen = 0f + var clearBlue = 0f + var clearAlpha = 1f - var fps = 0 - var fpsCount = 0 - var fpsCountTime = 0f + var fps = 0 + var fpsCount = 0 + var fpsCountTime = 0f - var borderLeft = 0 - var borderTop = 0 + var borderLeft = 0 + var borderTop = 0 - var focus = true + var focus = true - init { - window.onfocus = { - //println("GOT FOCUS!") + init { + window.onfocus = { + //println("GOT FOCUS!") - focus = true - "" - } - window.onblur = { - //println("LOST FOCUS!") + focus = true + "" + } + window.onblur = { + //println("LOST FOCUS!") - focus = false - "" - } - + focus = false + "" } - fun gl() = html.webgl + } - fun resize() { - val canvas = gl().canvas + fun gl() = html.webgl - // Check if the canvas is not the same size. - val windowWidth = window.innerWidth.toInt() - val windowHeight = window.innerHeight.toInt() + fun resize() { + val canvas = gl().canvas - if (view.lastWindowWidth != windowWidth || - view.lastWindowHeight != windowHeight) { - view.lastWindowWidth = windowWidth - view.lastWindowHeight = windowHeight - view.windowWidth = windowWidth - view.windowHeight = windowHeight + // Check if the canvas is not the same size. + val windowWidth = window.innerWidth.toInt() + val windowHeight = window.innerHeight.toInt() - view.updateView() + if (view.lastWindowWidth != windowWidth || + view.lastWindowHeight != windowHeight) { + view.lastWindowWidth = windowWidth + view.lastWindowHeight = windowHeight + view.windowWidth = windowWidth + view.windowHeight = windowHeight - val textCanvas = html.canvas2d.canvas + view.updateView() - // Make the canvas the same size - canvas.width = view.width.toInt() - canvas.height = view.height.toInt() + val textCanvas = html.canvas2d.canvas - textCanvas.width = view.width.toInt() - textCanvas.height = view.height.toInt() + // Make the canvas the same size + canvas.width = view.width.toInt() + canvas.height = view.height.toInt() - gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) + textCanvas.width = view.width.toInt() + textCanvas.height = view.height.toInt() - borderLeft = (windowWidth - view.windowWidth) / 2 - borderTop = (windowHeight - view.windowHeight) / 2 + gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) - canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) - textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) + borderLeft = (windowWidth - view.windowWidth) / 2 + borderTop = (windowHeight - view.windowHeight) / 2 + + canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + } + } + + fun start(startScreen: Screen) { + if (started) { + throw IllegalStateException("You can only start a game once!") + } + + setScreen(startScreen) + + // start game loop + started = true + gameLoop() + } + + fun setScreen(screen: Screen) { + currentScreen.unloadResources() + + currentScreen = screen + + screen.loadResources() + } + + fun setClearColor(r: Float, g: Float, b: Float, a: Float) { + clearRed = r + clearGreen = g + clearBlue = b + clearAlpha = a + } + + fun gameLoop() { + try { + if (!Textures.ready()) { + gl().clearColor(1f, 1f, 1f, 1f) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } else { + resize() + + if (!pause) { + html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); + + if (clearScreenEveryFrame) { + gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } + + gl().enable(WebGLRenderingContext.BLEND) + gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); + + val time = Date().getTime() + currentDelta = ((time - currentTime) / 1000f).toFloat() + currentTime = time + + val timeInSeconds = (currentTime - start) / 1000f + + fpsCountTime += currentDelta + fpsCount++ + while (fpsCountTime > 1f) { + fps = fpsCount + fpsCountTime -= 1f + fpsCount = 0 + } + + if (focus) { + currentScreen.update(timeInSeconds.toFloat(), currentDelta) + } + + currentScreen.render() } + } + } catch (e: Exception) { + println("Some error...") + console.log(e) } - fun start(startScreen: Screen) { - if (started) { - throw IllegalStateException("You can only start a game once!") - } - - setScreen(startScreen) - - // start game loop - started = true - gameLoop() + window.requestAnimationFrame { + gameLoop() } - - fun setScreen(screen: Screen) { - currentScreen.unloadResources() - - currentScreen = screen - - screen.loadResources() - } - - fun setClearColor(r: Float, g: Float, b: Float, a: Float) { - clearRed = r - clearGreen = g - clearBlue = b - clearAlpha = a - } - - fun gameLoop() { - try { - if (!Textures.ready()) { - gl().clearColor(1f, 1f, 1f, 1f) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } else { - resize() - - if (!pause) { - html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); - - if (clearScreenEveryFrame) { - gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } - - gl().enable(WebGLRenderingContext.BLEND) - gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); - - val time = Date().getTime() - currentDelta = ((time - currentTime) / 1000f).toFloat() - currentTime = time - - val timeInSeconds = (currentTime - start) / 1000f - - fpsCountTime += currentDelta - fpsCount++ - while (fpsCountTime > 1f) { - fps = fpsCount - fpsCountTime -= 1f - fpsCount = 0 - } - - if (focus) { - currentScreen.update(timeInSeconds.toFloat(), currentDelta) - } - - currentScreen.render() - } - } - } catch(e: Exception) { - println("Some error...") - console.log(e) - } - - window.requestAnimationFrame { - gameLoop() - } - } + } } diff --git a/src/main/kotlin/games/perses/game/Screen.kt b/src/main/kotlin/games/perses/game/Screen.kt index 10b6eae..7b381e7 100644 --- a/src/main/kotlin/games/perses/game/Screen.kt +++ b/src/main/kotlin/games/perses/game/Screen.kt @@ -8,31 +8,31 @@ abstract class Screen { - open fun loadResources() {} + open fun loadResources() {} - @Deprecated( + @Deprecated( message = "replace with unloadResources", replaceWith = ReplaceWith("unloadResources()") - ) - open fun closeResources() { - unloadResources() - } + ) + open fun closeResources() { + unloadResources() + } - open fun unloadResources() {} + open fun unloadResources() {} - abstract fun update(time: Float, delta: Float) + abstract fun update(time: Float, delta: Float) - abstract fun render() + abstract fun render() } -class DefaultScreen: Screen() { - override fun update(time: Float, delta: Float) { - } +class DefaultScreen : Screen() { + override fun update(time: Float, delta: Float) { + } - override fun render() { - // show loading message? - Game.gl().clearColor(1f, 1f, 0f, 1f) - Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } + override fun render() { + // show loading message? + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } } diff --git a/src/main/kotlin/games/perses/game/View.kt b/src/main/kotlin/games/perses/game/View.kt index 540a44d..16c9913 100644 --- a/src/main/kotlin/games/perses/game/View.kt +++ b/src/main/kotlin/games/perses/game/View.kt @@ -4,39 +4,39 @@ import kotlin.browser.document enum class ViewType { - PROJECTION, - WIDTH, - HEIGHT, - ABSOLUTE + PROJECTION, + WIDTH, + HEIGHT, + ABSOLUTE } class View( - var lastWindowWidth: Int = 2000, - var lastWindowHeight: Int = 1000, - var windowWidth: Int = 2000, - var windowHeight: Int = 1000, - var width: Float = 1024f, - var height: Float = 1024f, - var angle: Float = 60f, - var near: Float = -0.1f, - var far: Float = -100f, - var minAspectRatio: Float = 1f, - var maxAspectRatio: Float = 1f, - var leftOffset: Int = 0, - var bottomOffset: Int = 0, - var viewType: ViewType = ViewType.WIDTH, - var drawMode: DrawMode = DrawMode.LINEAR) { - var vMatrix = Matrix4() - var aspectRatio = 1f + var lastWindowWidth: Int = 2000, + var lastWindowHeight: Int = 1000, + var windowWidth: Int = 2000, + var windowHeight: Int = 1000, + var width: Float = 1024f, + var height: Float = 1024f, + var angle: Float = 60f, + var near: Float = -0.1f, + var far: Float = -100f, + var minAspectRatio: Float = 1f, + var maxAspectRatio: Float = 1f, + var leftOffset: Int = 0, + var bottomOffset: Int = 0, + var viewType: ViewType = ViewType.WIDTH, + var drawMode: DrawMode = DrawMode.LINEAR) { + var vMatrix = Matrix4() + var aspectRatio = 1f - init { - updateView() - } + init { + updateView() + } - fun requestFullscreen() { - val element = document.body - //language=javascript - js(""" + fun requestFullscreen() { + val element = document.body + //language=javascript + js(""" if(element.requestFullscreen) { element.requestFullscreen(); } else if(element.mozRequestFullScreen) { @@ -47,10 +47,10 @@ element.msRequestFullscreen(); } """) - } + } - fun exitFullscreen() { - js(""" + fun exitFullscreen() { + js(""" if(document.exitFullscreen) { document.exitFullscreen(); } else if(document.mozCancelFullScreen) { @@ -59,178 +59,178 @@ document.webkitExitFullscreen(); } """) + } + + fun switchFullscreen() { + if (isFullscreen()) { + exitFullscreen() + } else { + requestFullscreen() + } + } + + fun isFullscreen(): Boolean { + val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + + return fse != undefined + } + + fun updateView() { + aspectRatio = windowWidth / windowHeight.toFloat() + + if (aspectRatio < minAspectRatio) { + aspectRatio = minAspectRatio + + windowHeight = (windowWidth / aspectRatio).toInt() } - fun switchFullscreen() { - if (isFullscreen()) { - exitFullscreen() - } else { - requestFullscreen() - } + if (aspectRatio > maxAspectRatio) { + aspectRatio = maxAspectRatio + + windowWidth = (windowHeight * aspectRatio).toInt() } - fun isFullscreen(): Boolean { - val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + when (viewType) { + ViewType.ABSOLUTE -> { + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.WIDTH -> { + height = width / aspectRatio - return fse != undefined + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.HEIGHT -> { + width = height * aspectRatio + + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.PROJECTION -> { + vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun updateView() { - aspectRatio = windowWidth / windowHeight.toFloat() + //println("width: $width, height: $height") + } - if (aspectRatio < minAspectRatio) { - aspectRatio = minAspectRatio + fun screenToGameCoordX(screenX: Float): Float { + var result = screenX - windowHeight = (windowWidth / aspectRatio).toInt() - } - - if (aspectRatio > maxAspectRatio) { - aspectRatio = maxAspectRatio - - windowWidth = (windowHeight * aspectRatio).toInt() - } - - when (viewType) { - ViewType.ABSOLUTE -> { - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.WIDTH -> { - height = width / aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.HEIGHT -> { - width = height * aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.PROJECTION -> { - vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } - - //println("width: $width, height: $height") + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = ((screenX - Game.borderLeft) * width / windowWidth) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordX(screenX: Float): Float { - var result = screenX + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( (screenX - Game.borderLeft) * width / windowWidth ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun screenToGameCoordY(screenY: Float): Float { + var result = screenY - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - ((screenY - Game.borderTop) * height / windowHeight) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordY(screenY: Float): Float { - var result = screenY + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( (screenY - Game.borderTop) * height / windowHeight ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordX(gameX: Float): Float { + var result = gameX + val normalizedX = gameX + (width / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = (gameX / width * windowWidth) + Game.borderLeft + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordX(gameX: Float): Float { - var result = gameX - val normalizedX = gameX + (width / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( gameX / width * windowWidth ) + Game.borderLeft - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordY(gameY: Float): Float { + var result = gameY + val normalizedY = gameY + (height / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - (gameY / height * windowHeight) + Game.borderTop + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordY(gameY: Float): Float { - var result = gameY - val normalizedY = gameY + (height / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( gameY / height * windowHeight ) + Game.borderTop - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun setToWidth(width: Float) { + this.width = width + this.viewType = ViewType.WIDTH - return result - } + updateView() + } - fun setToWidth(width: Float) { - this.width = width - this.viewType = ViewType.WIDTH + fun setToHeight(height: Float) { + this.height = height + this.viewType = ViewType.HEIGHT - updateView() - } + updateView() + } - fun setToHeight(height: Float) { - this.height = height - this.viewType = ViewType.HEIGHT + fun setProjection(angle: Float) { + this.angle = angle + this.viewType = ViewType.PROJECTION - updateView() - } + updateView() + } - fun setProjection(angle: Float) { - this.angle = angle - this.viewType = ViewType.PROJECTION + fun setNear(near: Float) { + this.near = near - updateView() - } + updateView() + } - fun setNear(near: Float) { - this.near = near + fun setFar(far: Float) { + this.far = far - updateView() - } - - fun setFar(far: Float) { - this.far = far - - updateView() - } + updateView() + } } \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml index 43edcc2..7ed1494 100644 --- a/.idea/modules/kudens_test.iml +++ b/.idea/modules/kudens_test.iml @@ -1,8 +1,9 @@ - + + $MODULE_DIR$/../../build/kotlinjs/kudens.js \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7ae9969..e7225a0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'perses.games' -version '1.1.6-SNAPSHOT' +version '1.1.7-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'idea' @@ -20,7 +20,7 @@ } buildscript { - ext.kotlin_version = '1.2.21' + ext.kotlin_version = '1.2.30' repositories { maven { url "http://nexus.astraeus.nl/nexus/content/groups/public" diff --git a/src/main/kotlin/games/perses/color/Color.kt b/src/main/kotlin/games/perses/color/Color.kt index 7f235b0..31b540f 100644 --- a/src/main/kotlin/games/perses/color/Color.kt +++ b/src/main/kotlin/games/perses/color/Color.kt @@ -10,107 +10,107 @@ object Color { - /** - * Converts an HSL color value to RGB. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes h, s, and l are contained in the set [0, 1] and - * returns r, g, and b in the set [0, 255]. + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. - * @param h The hue - * * - * @param s The saturation - * * - * @param l The lightness - * * - * @return int array, the RGB representation - */ - fun hslToRgb(h: Float, s: Float, l: Float): IntArray { - val r: Float - val g: Float - val b: Float + * @param h The hue + * * + * @param s The saturation + * * + * @param l The lightness + * * + * @return int array, the RGB representation + */ + fun hslToRgb(h: Float, s: Float, l: Float): IntArray { + val r: Float + val g: Float + val b: Float - if (s == 0f) { - b = l - g = b - r = g // achromatic - } else { - val q = if (l < 0.5f) l * (1 + s) else l + s - l * s - val p = 2 * l - q - r = hueToRgb(p, q, h + 1f / 3f) - g = hueToRgb(p, q, h) - b = hueToRgb(p, q, h - 1f / 3f) - } - val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) + if (s == 0f) { + b = l + g = b + r = g // achromatic + } else { + val q = if (l < 0.5f) l * (1 + s) else l + s - l * s + val p = 2 * l - q + r = hueToRgb(p, q, h + 1f / 3f) + g = hueToRgb(p, q, h) + b = hueToRgb(p, q, h - 1f / 3f) + } + val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) - return rgb + return rgb + } + + /** Helper method that converts hue to rgb */ + fun hueToRgb(p: Float, q: Float, t: Float): Float { + var lt = t + if (lt < 0f) { + lt += 1f + } + if (lt > 1f) { + lt -= 1f + } + if (lt < 1f / 6f) { + return p + (q - p) * 6f * lt + } + if (lt < 1f / 2f) { + return q + } + if (lt < 2f / 3f) { + return p + (q - p) * (2f / 3f - lt) * 6f + } + return p + } + + /** + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes pR, pG, and bpBare contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + + * @param pR The red color value + * * + * @param pG The green color value + * * + * @param pB The blue color value + * * + * @return float array, the HSL representation + */ + fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { + val r = pR / 255f + val g = pG / 255f + val b = pB / 255f + + val max = if (r > g && r > b) r else if (g > b) g else b + val min = if (r < g && r < b) r else if (g < b) g else b + + var h: Float + val s: Float + val l: Float + l = (max + min) / 2.0f + + if (max == min) { + s = 0.0f + h = s + } else { + val d = max - min + s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) + + if (r > g && r > b) + h = (g - b) / d + (if (g < b) 6.0f else 0.0f) + else if (g > b) + h = (b - r) / d + 2.0f + else + h = (r - g) / d + 4.0f + + h /= 6.0f } - /** Helper method that converts hue to rgb */ - fun hueToRgb(p: Float, q: Float, t: Float): Float { - var lt = t - if (lt < 0f) { - lt += 1f - } - if (lt > 1f) { - lt -= 1f - } - if (lt < 1f / 6f) { - return p + (q - p) * 6f * lt - } - if (lt < 1f / 2f) { - return q - } - if (lt < 2f / 3f) { - return p + (q - p) * (2f / 3f - lt) * 6f - } - return p - } - - /** - * Converts an RGB color value to HSL. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes pR, pG, and bpBare contained in the set [0, 255] and - * returns h, s, and l in the set [0, 1]. - - * @param pR The red color value - * * - * @param pG The green color value - * * - * @param pB The blue color value - * * - * @return float array, the HSL representation - */ - fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { - val r = pR / 255f - val g = pG / 255f - val b = pB / 255f - - val max = if (r > g && r > b) r else if (g > b) g else b - val min = if (r < g && r < b) r else if (g < b) g else b - - var h: Float - val s: Float - val l: Float - l = (max + min) / 2.0f - - if (max == min) { - s = 0.0f - h = s - } else { - val d = max - min - s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) - - if (r > g && r > b) - h = (g - b) / d + (if (g < b) 6.0f else 0.0f) - else if (g > b) - h = (b - r) / d + 2.0f - else - h = (r - g) / d + 4.0f - - h /= 6.0f - } - - val hsl = floatArrayOf(h, s, l) - return hsl - } + val hsl = floatArrayOf(h, s, l) + return hsl + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/game/Game.kt b/src/main/kotlin/games/perses/game/Game.kt index 0961316..1becee5 100644 --- a/src/main/kotlin/games/perses/game/Game.kt +++ b/src/main/kotlin/games/perses/game/Game.kt @@ -14,210 +14,210 @@ */ enum class DrawMode { - LINEAR, - NEAREST + LINEAR, + NEAREST } class HTMLElements { - var container: HTMLElement - var webgl: WebGLRenderingContext - var canvas2d: CanvasRenderingContext2D + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D - init { - container = document.createElement("div") as HTMLElement + init { + container = document.createElement("div") as HTMLElement - val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement - val canvas = document.createElement("canvas") as HTMLCanvasElement + val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + val canvas = document.createElement("canvas") as HTMLCanvasElement - container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") - webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" ) - canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" ) + container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;") - document.body!!.appendChild(container) - container.appendChild(webGlCanvas) - container.appendChild(canvas) + document.body!!.appendChild(container) + container.appendChild(webGlCanvas) + container.appendChild(canvas) - val canvas2dcanvas = canvas.getContext("2d") + val canvas2dcanvas = canvas.getContext("2d") - var webglcanvas = webGlCanvas.getContext("webgl") - if (webglcanvas == null) { - console.log("webgl context not found, trying experimental-webgl.") - webglcanvas = webGlCanvas.getContext("experimental-webgl") - } - - if (webglcanvas != null) { - webgl = webglcanvas as WebGLRenderingContext - } else { - console.log("webgl?", webglcanvas) - window.alert("Your browser doesn't seem to support webgl!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } - - if (canvas2dcanvas != null) { - canvas2d = canvas2dcanvas as CanvasRenderingContext2D - } else { - console.log("canvas2d?", canvas2dcanvas) - window.alert("Your browser doesn't seem to support 2d canvas!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } + var webglcanvas = webGlCanvas.getContext("webgl") + if (webglcanvas == null) { + console.log("webgl context not found, trying experimental-webgl.") + webglcanvas = webGlCanvas.getContext("experimental-webgl") } + + if (webglcanvas != null) { + webgl = webglcanvas as WebGLRenderingContext + } else { + console.log("webgl?", webglcanvas) + window.alert("Your browser doesn't seem to support webgl!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + + if (canvas2dcanvas != null) { + canvas2d = canvas2dcanvas as CanvasRenderingContext2D + } else { + console.log("canvas2d?", canvas2dcanvas) + window.alert("Your browser doesn't seem to support 2d canvas!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + } } object Game { - var started = false - val view: View = View() - val html: HTMLElements by lazy { HTMLElements() } - var currentScreen: Screen = DefaultScreen() - var start = Date().getTime() - var currentTime = start - var currentDelta = 0f - var pause: Boolean = false - var clearScreenEveryFrame = true + var started = false + val view: View = View() + val html: HTMLElements by lazy { HTMLElements() } + var currentScreen: Screen = DefaultScreen() + var start = Date().getTime() + var currentTime = start + var currentDelta = 0f + var pause: Boolean = false + var clearScreenEveryFrame = true - var clearRed = 0f - var clearGreen = 0f - var clearBlue = 0f - var clearAlpha = 1f + var clearRed = 0f + var clearGreen = 0f + var clearBlue = 0f + var clearAlpha = 1f - var fps = 0 - var fpsCount = 0 - var fpsCountTime = 0f + var fps = 0 + var fpsCount = 0 + var fpsCountTime = 0f - var borderLeft = 0 - var borderTop = 0 + var borderLeft = 0 + var borderTop = 0 - var focus = true + var focus = true - init { - window.onfocus = { - //println("GOT FOCUS!") + init { + window.onfocus = { + //println("GOT FOCUS!") - focus = true - "" - } - window.onblur = { - //println("LOST FOCUS!") + focus = true + "" + } + window.onblur = { + //println("LOST FOCUS!") - focus = false - "" - } - + focus = false + "" } - fun gl() = html.webgl + } - fun resize() { - val canvas = gl().canvas + fun gl() = html.webgl - // Check if the canvas is not the same size. - val windowWidth = window.innerWidth.toInt() - val windowHeight = window.innerHeight.toInt() + fun resize() { + val canvas = gl().canvas - if (view.lastWindowWidth != windowWidth || - view.lastWindowHeight != windowHeight) { - view.lastWindowWidth = windowWidth - view.lastWindowHeight = windowHeight - view.windowWidth = windowWidth - view.windowHeight = windowHeight + // Check if the canvas is not the same size. + val windowWidth = window.innerWidth.toInt() + val windowHeight = window.innerHeight.toInt() - view.updateView() + if (view.lastWindowWidth != windowWidth || + view.lastWindowHeight != windowHeight) { + view.lastWindowWidth = windowWidth + view.lastWindowHeight = windowHeight + view.windowWidth = windowWidth + view.windowHeight = windowHeight - val textCanvas = html.canvas2d.canvas + view.updateView() - // Make the canvas the same size - canvas.width = view.width.toInt() - canvas.height = view.height.toInt() + val textCanvas = html.canvas2d.canvas - textCanvas.width = view.width.toInt() - textCanvas.height = view.height.toInt() + // Make the canvas the same size + canvas.width = view.width.toInt() + canvas.height = view.height.toInt() - gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) + textCanvas.width = view.width.toInt() + textCanvas.height = view.height.toInt() - borderLeft = (windowWidth - view.windowWidth) / 2 - borderTop = (windowHeight - view.windowHeight) / 2 + gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) - canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) - textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) + borderLeft = (windowWidth - view.windowWidth) / 2 + borderTop = (windowHeight - view.windowHeight) / 2 + + canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + } + } + + fun start(startScreen: Screen) { + if (started) { + throw IllegalStateException("You can only start a game once!") + } + + setScreen(startScreen) + + // start game loop + started = true + gameLoop() + } + + fun setScreen(screen: Screen) { + currentScreen.unloadResources() + + currentScreen = screen + + screen.loadResources() + } + + fun setClearColor(r: Float, g: Float, b: Float, a: Float) { + clearRed = r + clearGreen = g + clearBlue = b + clearAlpha = a + } + + fun gameLoop() { + try { + if (!Textures.ready()) { + gl().clearColor(1f, 1f, 1f, 1f) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } else { + resize() + + if (!pause) { + html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); + + if (clearScreenEveryFrame) { + gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } + + gl().enable(WebGLRenderingContext.BLEND) + gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); + + val time = Date().getTime() + currentDelta = ((time - currentTime) / 1000f).toFloat() + currentTime = time + + val timeInSeconds = (currentTime - start) / 1000f + + fpsCountTime += currentDelta + fpsCount++ + while (fpsCountTime > 1f) { + fps = fpsCount + fpsCountTime -= 1f + fpsCount = 0 + } + + if (focus) { + currentScreen.update(timeInSeconds.toFloat(), currentDelta) + } + + currentScreen.render() } + } + } catch (e: Exception) { + println("Some error...") + console.log(e) } - fun start(startScreen: Screen) { - if (started) { - throw IllegalStateException("You can only start a game once!") - } - - setScreen(startScreen) - - // start game loop - started = true - gameLoop() + window.requestAnimationFrame { + gameLoop() } - - fun setScreen(screen: Screen) { - currentScreen.unloadResources() - - currentScreen = screen - - screen.loadResources() - } - - fun setClearColor(r: Float, g: Float, b: Float, a: Float) { - clearRed = r - clearGreen = g - clearBlue = b - clearAlpha = a - } - - fun gameLoop() { - try { - if (!Textures.ready()) { - gl().clearColor(1f, 1f, 1f, 1f) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } else { - resize() - - if (!pause) { - html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); - - if (clearScreenEveryFrame) { - gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } - - gl().enable(WebGLRenderingContext.BLEND) - gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); - - val time = Date().getTime() - currentDelta = ((time - currentTime) / 1000f).toFloat() - currentTime = time - - val timeInSeconds = (currentTime - start) / 1000f - - fpsCountTime += currentDelta - fpsCount++ - while (fpsCountTime > 1f) { - fps = fpsCount - fpsCountTime -= 1f - fpsCount = 0 - } - - if (focus) { - currentScreen.update(timeInSeconds.toFloat(), currentDelta) - } - - currentScreen.render() - } - } - } catch(e: Exception) { - println("Some error...") - console.log(e) - } - - window.requestAnimationFrame { - gameLoop() - } - } + } } diff --git a/src/main/kotlin/games/perses/game/Screen.kt b/src/main/kotlin/games/perses/game/Screen.kt index 10b6eae..7b381e7 100644 --- a/src/main/kotlin/games/perses/game/Screen.kt +++ b/src/main/kotlin/games/perses/game/Screen.kt @@ -8,31 +8,31 @@ abstract class Screen { - open fun loadResources() {} + open fun loadResources() {} - @Deprecated( + @Deprecated( message = "replace with unloadResources", replaceWith = ReplaceWith("unloadResources()") - ) - open fun closeResources() { - unloadResources() - } + ) + open fun closeResources() { + unloadResources() + } - open fun unloadResources() {} + open fun unloadResources() {} - abstract fun update(time: Float, delta: Float) + abstract fun update(time: Float, delta: Float) - abstract fun render() + abstract fun render() } -class DefaultScreen: Screen() { - override fun update(time: Float, delta: Float) { - } +class DefaultScreen : Screen() { + override fun update(time: Float, delta: Float) { + } - override fun render() { - // show loading message? - Game.gl().clearColor(1f, 1f, 0f, 1f) - Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } + override fun render() { + // show loading message? + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } } diff --git a/src/main/kotlin/games/perses/game/View.kt b/src/main/kotlin/games/perses/game/View.kt index 540a44d..16c9913 100644 --- a/src/main/kotlin/games/perses/game/View.kt +++ b/src/main/kotlin/games/perses/game/View.kt @@ -4,39 +4,39 @@ import kotlin.browser.document enum class ViewType { - PROJECTION, - WIDTH, - HEIGHT, - ABSOLUTE + PROJECTION, + WIDTH, + HEIGHT, + ABSOLUTE } class View( - var lastWindowWidth: Int = 2000, - var lastWindowHeight: Int = 1000, - var windowWidth: Int = 2000, - var windowHeight: Int = 1000, - var width: Float = 1024f, - var height: Float = 1024f, - var angle: Float = 60f, - var near: Float = -0.1f, - var far: Float = -100f, - var minAspectRatio: Float = 1f, - var maxAspectRatio: Float = 1f, - var leftOffset: Int = 0, - var bottomOffset: Int = 0, - var viewType: ViewType = ViewType.WIDTH, - var drawMode: DrawMode = DrawMode.LINEAR) { - var vMatrix = Matrix4() - var aspectRatio = 1f + var lastWindowWidth: Int = 2000, + var lastWindowHeight: Int = 1000, + var windowWidth: Int = 2000, + var windowHeight: Int = 1000, + var width: Float = 1024f, + var height: Float = 1024f, + var angle: Float = 60f, + var near: Float = -0.1f, + var far: Float = -100f, + var minAspectRatio: Float = 1f, + var maxAspectRatio: Float = 1f, + var leftOffset: Int = 0, + var bottomOffset: Int = 0, + var viewType: ViewType = ViewType.WIDTH, + var drawMode: DrawMode = DrawMode.LINEAR) { + var vMatrix = Matrix4() + var aspectRatio = 1f - init { - updateView() - } + init { + updateView() + } - fun requestFullscreen() { - val element = document.body - //language=javascript - js(""" + fun requestFullscreen() { + val element = document.body + //language=javascript + js(""" if(element.requestFullscreen) { element.requestFullscreen(); } else if(element.mozRequestFullScreen) { @@ -47,10 +47,10 @@ element.msRequestFullscreen(); } """) - } + } - fun exitFullscreen() { - js(""" + fun exitFullscreen() { + js(""" if(document.exitFullscreen) { document.exitFullscreen(); } else if(document.mozCancelFullScreen) { @@ -59,178 +59,178 @@ document.webkitExitFullscreen(); } """) + } + + fun switchFullscreen() { + if (isFullscreen()) { + exitFullscreen() + } else { + requestFullscreen() + } + } + + fun isFullscreen(): Boolean { + val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + + return fse != undefined + } + + fun updateView() { + aspectRatio = windowWidth / windowHeight.toFloat() + + if (aspectRatio < minAspectRatio) { + aspectRatio = minAspectRatio + + windowHeight = (windowWidth / aspectRatio).toInt() } - fun switchFullscreen() { - if (isFullscreen()) { - exitFullscreen() - } else { - requestFullscreen() - } + if (aspectRatio > maxAspectRatio) { + aspectRatio = maxAspectRatio + + windowWidth = (windowHeight * aspectRatio).toInt() } - fun isFullscreen(): Boolean { - val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + when (viewType) { + ViewType.ABSOLUTE -> { + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.WIDTH -> { + height = width / aspectRatio - return fse != undefined + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.HEIGHT -> { + width = height * aspectRatio + + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.PROJECTION -> { + vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun updateView() { - aspectRatio = windowWidth / windowHeight.toFloat() + //println("width: $width, height: $height") + } - if (aspectRatio < minAspectRatio) { - aspectRatio = minAspectRatio + fun screenToGameCoordX(screenX: Float): Float { + var result = screenX - windowHeight = (windowWidth / aspectRatio).toInt() - } - - if (aspectRatio > maxAspectRatio) { - aspectRatio = maxAspectRatio - - windowWidth = (windowHeight * aspectRatio).toInt() - } - - when (viewType) { - ViewType.ABSOLUTE -> { - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.WIDTH -> { - height = width / aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.HEIGHT -> { - width = height * aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.PROJECTION -> { - vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } - - //println("width: $width, height: $height") + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = ((screenX - Game.borderLeft) * width / windowWidth) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordX(screenX: Float): Float { - var result = screenX + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( (screenX - Game.borderLeft) * width / windowWidth ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun screenToGameCoordY(screenY: Float): Float { + var result = screenY - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - ((screenY - Game.borderTop) * height / windowHeight) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordY(screenY: Float): Float { - var result = screenY + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( (screenY - Game.borderTop) * height / windowHeight ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordX(gameX: Float): Float { + var result = gameX + val normalizedX = gameX + (width / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = (gameX / width * windowWidth) + Game.borderLeft + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordX(gameX: Float): Float { - var result = gameX - val normalizedX = gameX + (width / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( gameX / width * windowWidth ) + Game.borderLeft - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordY(gameY: Float): Float { + var result = gameY + val normalizedY = gameY + (height / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - (gameY / height * windowHeight) + Game.borderTop + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordY(gameY: Float): Float { - var result = gameY - val normalizedY = gameY + (height / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( gameY / height * windowHeight ) + Game.borderTop - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun setToWidth(width: Float) { + this.width = width + this.viewType = ViewType.WIDTH - return result - } + updateView() + } - fun setToWidth(width: Float) { - this.width = width - this.viewType = ViewType.WIDTH + fun setToHeight(height: Float) { + this.height = height + this.viewType = ViewType.HEIGHT - updateView() - } + updateView() + } - fun setToHeight(height: Float) { - this.height = height - this.viewType = ViewType.HEIGHT + fun setProjection(angle: Float) { + this.angle = angle + this.viewType = ViewType.PROJECTION - updateView() - } + updateView() + } - fun setProjection(angle: Float) { - this.angle = angle - this.viewType = ViewType.PROJECTION + fun setNear(near: Float) { + this.near = near - updateView() - } + updateView() + } - fun setNear(near: Float) { - this.near = near + fun setFar(far: Float) { + this.far = far - updateView() - } - - fun setFar(far: Float) { - this.far = far - - updateView() - } + updateView() + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/input/Input.kt b/src/main/kotlin/games/perses/input/Input.kt index 71a3adc..58c4f23 100644 --- a/src/main/kotlin/games/perses/input/Input.kt +++ b/src/main/kotlin/games/perses/input/Input.kt @@ -15,235 +15,235 @@ */ enum class KeyCode(val keyCode: Int) { - BACKSPACE(8), - TAB(9), - ENTER(13), - SHIFT(16), - CTRL(17), - ALT(18), - PAUSE_BREAK(19), - CAPS_LOCK(20), - ESCAPE(27), - SPACE(32), - PAGE_UP(33), - PAGE_DOWN(34), - END(35), - HOME(36), - LEFT_ARROW(37), - UP_ARROW(38), - RIGHT_ARROW(39), - DOWN_ARROW(40), - INSERT(45), - DELETE(46), - NR_0(48), - NR_1(49), - NR_2(50), - NR_3(51), - NR_4(52), - NR_5(53), - NR_6(54), - NR_7(55), - NR_8(56), - NR_9(57), - A(65), - B(66), - C(67), - D(68), - E(69), - F(70), - G(71), - H(72), - I(73), - J(74), - K(75), - L(76), - M(77), - N(78), - O(79), - P(80), - Q(81), - R(82), - S(83), - T(84), - U(85), - V(86), - W(87), - X(88), - Y(89), - Z(90), - LEFT_WINDOW_KEY(91), - RIGHT_WINDOW_KEY(92), - SELECT_KEY(93), - NUMPAD_0(96), - NUMPAD_1(97), - NUMPAD_2(98), - NUMPAD_3(99), - NUMPAD_4(100), - NUMPAD_5(101), - NUMPAD_6(102), - NUMPAD_7(103), - NUMPAD_8(104), - NUMPAD_9(105), - MULTIPLY(106), - ADD(107), - SUBTRACT(109), - DECIMAL_POINT(110), - DIVIDE(111), - F1(112), - F2(113), - F3(114), - F4(115), - F5(116), - F6(117), - F7(118), - F8(119), - F9(120), - F10(121), - F11(122), - F12(123), - NUM_LOCK(144), - SCROLL_LOCK(145), - SEMI_COLON(186), - EQUAL_SIGN(187), - COMMA(188), - DASH(189), - PERIOD(190), - FORWARD_SLASH(191), - GRAVE_ACCENT(192), - OPEN_BRACKET(219), - BACK_SLASH(220), - CLOSE_BRAKET(221), - SINGLE_QUOTE(222), + BACKSPACE(8), + TAB(9), + ENTER(13), + SHIFT(16), + CTRL(17), + ALT(18), + PAUSE_BREAK(19), + CAPS_LOCK(20), + ESCAPE(27), + SPACE(32), + PAGE_UP(33), + PAGE_DOWN(34), + END(35), + HOME(36), + LEFT_ARROW(37), + UP_ARROW(38), + RIGHT_ARROW(39), + DOWN_ARROW(40), + INSERT(45), + DELETE(46), + NR_0(48), + NR_1(49), + NR_2(50), + NR_3(51), + NR_4(52), + NR_5(53), + NR_6(54), + NR_7(55), + NR_8(56), + NR_9(57), + A(65), + B(66), + C(67), + D(68), + E(69), + F(70), + G(71), + H(72), + I(73), + J(74), + K(75), + L(76), + M(77), + N(78), + O(79), + P(80), + Q(81), + R(82), + S(83), + T(84), + U(85), + V(86), + W(87), + X(88), + Y(89), + Z(90), + LEFT_WINDOW_KEY(91), + RIGHT_WINDOW_KEY(92), + SELECT_KEY(93), + NUMPAD_0(96), + NUMPAD_1(97), + NUMPAD_2(98), + NUMPAD_3(99), + NUMPAD_4(100), + NUMPAD_5(101), + NUMPAD_6(102), + NUMPAD_7(103), + NUMPAD_8(104), + NUMPAD_9(105), + MULTIPLY(106), + ADD(107), + SUBTRACT(109), + DECIMAL_POINT(110), + DIVIDE(111), + F1(112), + F2(113), + F3(114), + F4(115), + F5(116), + F6(117), + F7(118), + F8(119), + F9(120), + F10(121), + F11(122), + F12(123), + NUM_LOCK(144), + SCROLL_LOCK(145), + SEMI_COLON(186), + EQUAL_SIGN(187), + COMMA(188), + DASH(189), + PERIOD(190), + FORWARD_SLASH(191), + GRAVE_ACCENT(192), + OPEN_BRACKET(219), + BACK_SLASH(220), + CLOSE_BRAKET(221), + SINGLE_QUOTE(222), - ESC(27), - LEFT(37), - UP(38), - DOWN(40), - RIGHT(39), - MINUS(109), - PLUS(107), + ESC(27), + LEFT(37), + UP(38), + DOWN(40), + RIGHT(39), + MINUS(109), + PLUS(107), } interface InputProcessor { - fun keyPressed(charCode: Int) + fun keyPressed(charCode: Int) - fun keyDown(keyCode: Int) + fun keyDown(keyCode: Int) - fun keyUp(keyCode: Int) + fun keyUp(keyCode: Int) - fun pointerClick(pointer: Int, x: Float, y: Float) + fun pointerClick(pointer: Int, x: Float, y: Float) - fun mouseMove(x: Float, y: Float) + fun mouseMove(x: Float, y: Float) } open class EmptyInputProcessor : InputProcessor { - override fun pointerClick(pointer: Int, x: Float, y: Float) { } + override fun pointerClick(pointer: Int, x: Float, y: Float) {} - override fun keyDown(keyCode: Int) { } + override fun keyDown(keyCode: Int) {} - override fun keyPressed(charCode: Int) { } + override fun keyPressed(charCode: Int) {} - override fun keyUp(keyCode: Int) { } + override fun keyUp(keyCode: Int) {} - override fun mouseMove(x: Float, y: Float) { } + override fun mouseMove(x: Float, y: Float) {} } object Input { - private val keys: MutableMap = HashMap() - private var inputProcesser: InputProcessor = EmptyInputProcessor() + private val keys: MutableMap = HashMap() + private var inputProcesser: InputProcessor = EmptyInputProcessor() - init { - val body = document.body - if (body != null) { - body.onkeydown = { - keyDown(it) - } + init { + val body = document.body + if (body != null) { + body.onkeydown = { + keyDown(it) + } - body.onkeyup = { - keyUp(it) - } + body.onkeyup = { + keyUp(it) + } - body.onkeypress = { - keyPress(it) - } + body.onkeypress = { + keyPress(it) + } - body.onclick = { - mouseClick(it) - } + body.onclick = { + mouseClick(it) + } - body.onmousedown = { - mouseMove(it) - } + body.onmousedown = { + mouseMove(it) + } - body.onmouseup = { - mouseMove(it) - } + body.onmouseup = { + mouseMove(it) + } - body.onmousemove = { - mouseMove(it) - } - } else { - console.log("Can't register key events, document.body is null!?") - } + body.onmousemove = { + mouseMove(it) + } + } else { + console.log("Can't register key events, document.body is null!?") } + } - fun setInputProcessor(processor: InputProcessor) { - this.inputProcesser = processor + fun setInputProcessor(processor: InputProcessor) { + this.inputProcesser = processor + } + + private fun keyDown(key: Event) { + if (key is KeyboardEvent) { + keys.put(key.keyCode, Date().getTime()) + + inputProcesser.keyDown(key.keyCode) } + } - private fun keyDown(key: Event) { - if (key is KeyboardEvent) { - keys.put(key.keyCode, Date().getTime()) + private fun keyUp(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyUp(key.keyCode) - inputProcesser.keyDown(key.keyCode) - } + keys.remove(key.keyCode) } + } - private fun keyUp(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyUp(key.keyCode) - - keys.remove(key.keyCode) - } + private fun keyPress(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyPressed(key.charCode) } + } - private fun keyPress(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyPressed(key.charCode) - } + private fun mouseClick(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + + inputProcesser.pointerClick(event.button.toInt(), vx, vy) } + } - private fun mouseClick(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + private fun mouseMove(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) - inputProcesser.pointerClick(event.button.toInt(), vx, vy) - } + inputProcesser.mouseMove(vx, vy) } + } - private fun mouseMove(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + fun isDown(keyCode: Int) = keys.containsKey(keyCode) - inputProcesser.mouseMove(vx, vy) - } - } + fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - fun isDown(keyCode: Int) = keys.containsKey(keyCode) + fun wasPressed(keyCode: Int, delta: Double): Boolean { + val time = keys[keyCode] - fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - - fun wasPressed(keyCode: Int, delta: Double): Boolean { - val time = keys[keyCode] - - return (time != null && time > (Date().getTime() - delta)) - } + return (time != null && time > (Date().getTime() - delta)) + } } diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml index 43edcc2..7ed1494 100644 --- a/.idea/modules/kudens_test.iml +++ b/.idea/modules/kudens_test.iml @@ -1,8 +1,9 @@ - + + $MODULE_DIR$/../../build/kotlinjs/kudens.js \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7ae9969..e7225a0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'perses.games' -version '1.1.6-SNAPSHOT' +version '1.1.7-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'idea' @@ -20,7 +20,7 @@ } buildscript { - ext.kotlin_version = '1.2.21' + ext.kotlin_version = '1.2.30' repositories { maven { url "http://nexus.astraeus.nl/nexus/content/groups/public" diff --git a/src/main/kotlin/games/perses/color/Color.kt b/src/main/kotlin/games/perses/color/Color.kt index 7f235b0..31b540f 100644 --- a/src/main/kotlin/games/perses/color/Color.kt +++ b/src/main/kotlin/games/perses/color/Color.kt @@ -10,107 +10,107 @@ object Color { - /** - * Converts an HSL color value to RGB. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes h, s, and l are contained in the set [0, 1] and - * returns r, g, and b in the set [0, 255]. + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. - * @param h The hue - * * - * @param s The saturation - * * - * @param l The lightness - * * - * @return int array, the RGB representation - */ - fun hslToRgb(h: Float, s: Float, l: Float): IntArray { - val r: Float - val g: Float - val b: Float + * @param h The hue + * * + * @param s The saturation + * * + * @param l The lightness + * * + * @return int array, the RGB representation + */ + fun hslToRgb(h: Float, s: Float, l: Float): IntArray { + val r: Float + val g: Float + val b: Float - if (s == 0f) { - b = l - g = b - r = g // achromatic - } else { - val q = if (l < 0.5f) l * (1 + s) else l + s - l * s - val p = 2 * l - q - r = hueToRgb(p, q, h + 1f / 3f) - g = hueToRgb(p, q, h) - b = hueToRgb(p, q, h - 1f / 3f) - } - val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) + if (s == 0f) { + b = l + g = b + r = g // achromatic + } else { + val q = if (l < 0.5f) l * (1 + s) else l + s - l * s + val p = 2 * l - q + r = hueToRgb(p, q, h + 1f / 3f) + g = hueToRgb(p, q, h) + b = hueToRgb(p, q, h - 1f / 3f) + } + val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) - return rgb + return rgb + } + + /** Helper method that converts hue to rgb */ + fun hueToRgb(p: Float, q: Float, t: Float): Float { + var lt = t + if (lt < 0f) { + lt += 1f + } + if (lt > 1f) { + lt -= 1f + } + if (lt < 1f / 6f) { + return p + (q - p) * 6f * lt + } + if (lt < 1f / 2f) { + return q + } + if (lt < 2f / 3f) { + return p + (q - p) * (2f / 3f - lt) * 6f + } + return p + } + + /** + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes pR, pG, and bpBare contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + + * @param pR The red color value + * * + * @param pG The green color value + * * + * @param pB The blue color value + * * + * @return float array, the HSL representation + */ + fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { + val r = pR / 255f + val g = pG / 255f + val b = pB / 255f + + val max = if (r > g && r > b) r else if (g > b) g else b + val min = if (r < g && r < b) r else if (g < b) g else b + + var h: Float + val s: Float + val l: Float + l = (max + min) / 2.0f + + if (max == min) { + s = 0.0f + h = s + } else { + val d = max - min + s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) + + if (r > g && r > b) + h = (g - b) / d + (if (g < b) 6.0f else 0.0f) + else if (g > b) + h = (b - r) / d + 2.0f + else + h = (r - g) / d + 4.0f + + h /= 6.0f } - /** Helper method that converts hue to rgb */ - fun hueToRgb(p: Float, q: Float, t: Float): Float { - var lt = t - if (lt < 0f) { - lt += 1f - } - if (lt > 1f) { - lt -= 1f - } - if (lt < 1f / 6f) { - return p + (q - p) * 6f * lt - } - if (lt < 1f / 2f) { - return q - } - if (lt < 2f / 3f) { - return p + (q - p) * (2f / 3f - lt) * 6f - } - return p - } - - /** - * Converts an RGB color value to HSL. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes pR, pG, and bpBare contained in the set [0, 255] and - * returns h, s, and l in the set [0, 1]. - - * @param pR The red color value - * * - * @param pG The green color value - * * - * @param pB The blue color value - * * - * @return float array, the HSL representation - */ - fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { - val r = pR / 255f - val g = pG / 255f - val b = pB / 255f - - val max = if (r > g && r > b) r else if (g > b) g else b - val min = if (r < g && r < b) r else if (g < b) g else b - - var h: Float - val s: Float - val l: Float - l = (max + min) / 2.0f - - if (max == min) { - s = 0.0f - h = s - } else { - val d = max - min - s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) - - if (r > g && r > b) - h = (g - b) / d + (if (g < b) 6.0f else 0.0f) - else if (g > b) - h = (b - r) / d + 2.0f - else - h = (r - g) / d + 4.0f - - h /= 6.0f - } - - val hsl = floatArrayOf(h, s, l) - return hsl - } + val hsl = floatArrayOf(h, s, l) + return hsl + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/game/Game.kt b/src/main/kotlin/games/perses/game/Game.kt index 0961316..1becee5 100644 --- a/src/main/kotlin/games/perses/game/Game.kt +++ b/src/main/kotlin/games/perses/game/Game.kt @@ -14,210 +14,210 @@ */ enum class DrawMode { - LINEAR, - NEAREST + LINEAR, + NEAREST } class HTMLElements { - var container: HTMLElement - var webgl: WebGLRenderingContext - var canvas2d: CanvasRenderingContext2D + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D - init { - container = document.createElement("div") as HTMLElement + init { + container = document.createElement("div") as HTMLElement - val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement - val canvas = document.createElement("canvas") as HTMLCanvasElement + val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + val canvas = document.createElement("canvas") as HTMLCanvasElement - container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") - webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" ) - canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" ) + container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;") - document.body!!.appendChild(container) - container.appendChild(webGlCanvas) - container.appendChild(canvas) + document.body!!.appendChild(container) + container.appendChild(webGlCanvas) + container.appendChild(canvas) - val canvas2dcanvas = canvas.getContext("2d") + val canvas2dcanvas = canvas.getContext("2d") - var webglcanvas = webGlCanvas.getContext("webgl") - if (webglcanvas == null) { - console.log("webgl context not found, trying experimental-webgl.") - webglcanvas = webGlCanvas.getContext("experimental-webgl") - } - - if (webglcanvas != null) { - webgl = webglcanvas as WebGLRenderingContext - } else { - console.log("webgl?", webglcanvas) - window.alert("Your browser doesn't seem to support webgl!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } - - if (canvas2dcanvas != null) { - canvas2d = canvas2dcanvas as CanvasRenderingContext2D - } else { - console.log("canvas2d?", canvas2dcanvas) - window.alert("Your browser doesn't seem to support 2d canvas!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } + var webglcanvas = webGlCanvas.getContext("webgl") + if (webglcanvas == null) { + console.log("webgl context not found, trying experimental-webgl.") + webglcanvas = webGlCanvas.getContext("experimental-webgl") } + + if (webglcanvas != null) { + webgl = webglcanvas as WebGLRenderingContext + } else { + console.log("webgl?", webglcanvas) + window.alert("Your browser doesn't seem to support webgl!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + + if (canvas2dcanvas != null) { + canvas2d = canvas2dcanvas as CanvasRenderingContext2D + } else { + console.log("canvas2d?", canvas2dcanvas) + window.alert("Your browser doesn't seem to support 2d canvas!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + } } object Game { - var started = false - val view: View = View() - val html: HTMLElements by lazy { HTMLElements() } - var currentScreen: Screen = DefaultScreen() - var start = Date().getTime() - var currentTime = start - var currentDelta = 0f - var pause: Boolean = false - var clearScreenEveryFrame = true + var started = false + val view: View = View() + val html: HTMLElements by lazy { HTMLElements() } + var currentScreen: Screen = DefaultScreen() + var start = Date().getTime() + var currentTime = start + var currentDelta = 0f + var pause: Boolean = false + var clearScreenEveryFrame = true - var clearRed = 0f - var clearGreen = 0f - var clearBlue = 0f - var clearAlpha = 1f + var clearRed = 0f + var clearGreen = 0f + var clearBlue = 0f + var clearAlpha = 1f - var fps = 0 - var fpsCount = 0 - var fpsCountTime = 0f + var fps = 0 + var fpsCount = 0 + var fpsCountTime = 0f - var borderLeft = 0 - var borderTop = 0 + var borderLeft = 0 + var borderTop = 0 - var focus = true + var focus = true - init { - window.onfocus = { - //println("GOT FOCUS!") + init { + window.onfocus = { + //println("GOT FOCUS!") - focus = true - "" - } - window.onblur = { - //println("LOST FOCUS!") + focus = true + "" + } + window.onblur = { + //println("LOST FOCUS!") - focus = false - "" - } - + focus = false + "" } - fun gl() = html.webgl + } - fun resize() { - val canvas = gl().canvas + fun gl() = html.webgl - // Check if the canvas is not the same size. - val windowWidth = window.innerWidth.toInt() - val windowHeight = window.innerHeight.toInt() + fun resize() { + val canvas = gl().canvas - if (view.lastWindowWidth != windowWidth || - view.lastWindowHeight != windowHeight) { - view.lastWindowWidth = windowWidth - view.lastWindowHeight = windowHeight - view.windowWidth = windowWidth - view.windowHeight = windowHeight + // Check if the canvas is not the same size. + val windowWidth = window.innerWidth.toInt() + val windowHeight = window.innerHeight.toInt() - view.updateView() + if (view.lastWindowWidth != windowWidth || + view.lastWindowHeight != windowHeight) { + view.lastWindowWidth = windowWidth + view.lastWindowHeight = windowHeight + view.windowWidth = windowWidth + view.windowHeight = windowHeight - val textCanvas = html.canvas2d.canvas + view.updateView() - // Make the canvas the same size - canvas.width = view.width.toInt() - canvas.height = view.height.toInt() + val textCanvas = html.canvas2d.canvas - textCanvas.width = view.width.toInt() - textCanvas.height = view.height.toInt() + // Make the canvas the same size + canvas.width = view.width.toInt() + canvas.height = view.height.toInt() - gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) + textCanvas.width = view.width.toInt() + textCanvas.height = view.height.toInt() - borderLeft = (windowWidth - view.windowWidth) / 2 - borderTop = (windowHeight - view.windowHeight) / 2 + gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) - canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) - textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) + borderLeft = (windowWidth - view.windowWidth) / 2 + borderTop = (windowHeight - view.windowHeight) / 2 + + canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + } + } + + fun start(startScreen: Screen) { + if (started) { + throw IllegalStateException("You can only start a game once!") + } + + setScreen(startScreen) + + // start game loop + started = true + gameLoop() + } + + fun setScreen(screen: Screen) { + currentScreen.unloadResources() + + currentScreen = screen + + screen.loadResources() + } + + fun setClearColor(r: Float, g: Float, b: Float, a: Float) { + clearRed = r + clearGreen = g + clearBlue = b + clearAlpha = a + } + + fun gameLoop() { + try { + if (!Textures.ready()) { + gl().clearColor(1f, 1f, 1f, 1f) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } else { + resize() + + if (!pause) { + html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); + + if (clearScreenEveryFrame) { + gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } + + gl().enable(WebGLRenderingContext.BLEND) + gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); + + val time = Date().getTime() + currentDelta = ((time - currentTime) / 1000f).toFloat() + currentTime = time + + val timeInSeconds = (currentTime - start) / 1000f + + fpsCountTime += currentDelta + fpsCount++ + while (fpsCountTime > 1f) { + fps = fpsCount + fpsCountTime -= 1f + fpsCount = 0 + } + + if (focus) { + currentScreen.update(timeInSeconds.toFloat(), currentDelta) + } + + currentScreen.render() } + } + } catch (e: Exception) { + println("Some error...") + console.log(e) } - fun start(startScreen: Screen) { - if (started) { - throw IllegalStateException("You can only start a game once!") - } - - setScreen(startScreen) - - // start game loop - started = true - gameLoop() + window.requestAnimationFrame { + gameLoop() } - - fun setScreen(screen: Screen) { - currentScreen.unloadResources() - - currentScreen = screen - - screen.loadResources() - } - - fun setClearColor(r: Float, g: Float, b: Float, a: Float) { - clearRed = r - clearGreen = g - clearBlue = b - clearAlpha = a - } - - fun gameLoop() { - try { - if (!Textures.ready()) { - gl().clearColor(1f, 1f, 1f, 1f) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } else { - resize() - - if (!pause) { - html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); - - if (clearScreenEveryFrame) { - gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } - - gl().enable(WebGLRenderingContext.BLEND) - gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); - - val time = Date().getTime() - currentDelta = ((time - currentTime) / 1000f).toFloat() - currentTime = time - - val timeInSeconds = (currentTime - start) / 1000f - - fpsCountTime += currentDelta - fpsCount++ - while (fpsCountTime > 1f) { - fps = fpsCount - fpsCountTime -= 1f - fpsCount = 0 - } - - if (focus) { - currentScreen.update(timeInSeconds.toFloat(), currentDelta) - } - - currentScreen.render() - } - } - } catch(e: Exception) { - println("Some error...") - console.log(e) - } - - window.requestAnimationFrame { - gameLoop() - } - } + } } diff --git a/src/main/kotlin/games/perses/game/Screen.kt b/src/main/kotlin/games/perses/game/Screen.kt index 10b6eae..7b381e7 100644 --- a/src/main/kotlin/games/perses/game/Screen.kt +++ b/src/main/kotlin/games/perses/game/Screen.kt @@ -8,31 +8,31 @@ abstract class Screen { - open fun loadResources() {} + open fun loadResources() {} - @Deprecated( + @Deprecated( message = "replace with unloadResources", replaceWith = ReplaceWith("unloadResources()") - ) - open fun closeResources() { - unloadResources() - } + ) + open fun closeResources() { + unloadResources() + } - open fun unloadResources() {} + open fun unloadResources() {} - abstract fun update(time: Float, delta: Float) + abstract fun update(time: Float, delta: Float) - abstract fun render() + abstract fun render() } -class DefaultScreen: Screen() { - override fun update(time: Float, delta: Float) { - } +class DefaultScreen : Screen() { + override fun update(time: Float, delta: Float) { + } - override fun render() { - // show loading message? - Game.gl().clearColor(1f, 1f, 0f, 1f) - Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } + override fun render() { + // show loading message? + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } } diff --git a/src/main/kotlin/games/perses/game/View.kt b/src/main/kotlin/games/perses/game/View.kt index 540a44d..16c9913 100644 --- a/src/main/kotlin/games/perses/game/View.kt +++ b/src/main/kotlin/games/perses/game/View.kt @@ -4,39 +4,39 @@ import kotlin.browser.document enum class ViewType { - PROJECTION, - WIDTH, - HEIGHT, - ABSOLUTE + PROJECTION, + WIDTH, + HEIGHT, + ABSOLUTE } class View( - var lastWindowWidth: Int = 2000, - var lastWindowHeight: Int = 1000, - var windowWidth: Int = 2000, - var windowHeight: Int = 1000, - var width: Float = 1024f, - var height: Float = 1024f, - var angle: Float = 60f, - var near: Float = -0.1f, - var far: Float = -100f, - var minAspectRatio: Float = 1f, - var maxAspectRatio: Float = 1f, - var leftOffset: Int = 0, - var bottomOffset: Int = 0, - var viewType: ViewType = ViewType.WIDTH, - var drawMode: DrawMode = DrawMode.LINEAR) { - var vMatrix = Matrix4() - var aspectRatio = 1f + var lastWindowWidth: Int = 2000, + var lastWindowHeight: Int = 1000, + var windowWidth: Int = 2000, + var windowHeight: Int = 1000, + var width: Float = 1024f, + var height: Float = 1024f, + var angle: Float = 60f, + var near: Float = -0.1f, + var far: Float = -100f, + var minAspectRatio: Float = 1f, + var maxAspectRatio: Float = 1f, + var leftOffset: Int = 0, + var bottomOffset: Int = 0, + var viewType: ViewType = ViewType.WIDTH, + var drawMode: DrawMode = DrawMode.LINEAR) { + var vMatrix = Matrix4() + var aspectRatio = 1f - init { - updateView() - } + init { + updateView() + } - fun requestFullscreen() { - val element = document.body - //language=javascript - js(""" + fun requestFullscreen() { + val element = document.body + //language=javascript + js(""" if(element.requestFullscreen) { element.requestFullscreen(); } else if(element.mozRequestFullScreen) { @@ -47,10 +47,10 @@ element.msRequestFullscreen(); } """) - } + } - fun exitFullscreen() { - js(""" + fun exitFullscreen() { + js(""" if(document.exitFullscreen) { document.exitFullscreen(); } else if(document.mozCancelFullScreen) { @@ -59,178 +59,178 @@ document.webkitExitFullscreen(); } """) + } + + fun switchFullscreen() { + if (isFullscreen()) { + exitFullscreen() + } else { + requestFullscreen() + } + } + + fun isFullscreen(): Boolean { + val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + + return fse != undefined + } + + fun updateView() { + aspectRatio = windowWidth / windowHeight.toFloat() + + if (aspectRatio < minAspectRatio) { + aspectRatio = minAspectRatio + + windowHeight = (windowWidth / aspectRatio).toInt() } - fun switchFullscreen() { - if (isFullscreen()) { - exitFullscreen() - } else { - requestFullscreen() - } + if (aspectRatio > maxAspectRatio) { + aspectRatio = maxAspectRatio + + windowWidth = (windowHeight * aspectRatio).toInt() } - fun isFullscreen(): Boolean { - val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + when (viewType) { + ViewType.ABSOLUTE -> { + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.WIDTH -> { + height = width / aspectRatio - return fse != undefined + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.HEIGHT -> { + width = height * aspectRatio + + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.PROJECTION -> { + vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun updateView() { - aspectRatio = windowWidth / windowHeight.toFloat() + //println("width: $width, height: $height") + } - if (aspectRatio < minAspectRatio) { - aspectRatio = minAspectRatio + fun screenToGameCoordX(screenX: Float): Float { + var result = screenX - windowHeight = (windowWidth / aspectRatio).toInt() - } - - if (aspectRatio > maxAspectRatio) { - aspectRatio = maxAspectRatio - - windowWidth = (windowHeight * aspectRatio).toInt() - } - - when (viewType) { - ViewType.ABSOLUTE -> { - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.WIDTH -> { - height = width / aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.HEIGHT -> { - width = height * aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.PROJECTION -> { - vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } - - //println("width: $width, height: $height") + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = ((screenX - Game.borderLeft) * width / windowWidth) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordX(screenX: Float): Float { - var result = screenX + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( (screenX - Game.borderLeft) * width / windowWidth ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun screenToGameCoordY(screenY: Float): Float { + var result = screenY - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - ((screenY - Game.borderTop) * height / windowHeight) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordY(screenY: Float): Float { - var result = screenY + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( (screenY - Game.borderTop) * height / windowHeight ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordX(gameX: Float): Float { + var result = gameX + val normalizedX = gameX + (width / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = (gameX / width * windowWidth) + Game.borderLeft + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordX(gameX: Float): Float { - var result = gameX - val normalizedX = gameX + (width / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( gameX / width * windowWidth ) + Game.borderLeft - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordY(gameY: Float): Float { + var result = gameY + val normalizedY = gameY + (height / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - (gameY / height * windowHeight) + Game.borderTop + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordY(gameY: Float): Float { - var result = gameY - val normalizedY = gameY + (height / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( gameY / height * windowHeight ) + Game.borderTop - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun setToWidth(width: Float) { + this.width = width + this.viewType = ViewType.WIDTH - return result - } + updateView() + } - fun setToWidth(width: Float) { - this.width = width - this.viewType = ViewType.WIDTH + fun setToHeight(height: Float) { + this.height = height + this.viewType = ViewType.HEIGHT - updateView() - } + updateView() + } - fun setToHeight(height: Float) { - this.height = height - this.viewType = ViewType.HEIGHT + fun setProjection(angle: Float) { + this.angle = angle + this.viewType = ViewType.PROJECTION - updateView() - } + updateView() + } - fun setProjection(angle: Float) { - this.angle = angle - this.viewType = ViewType.PROJECTION + fun setNear(near: Float) { + this.near = near - updateView() - } + updateView() + } - fun setNear(near: Float) { - this.near = near + fun setFar(far: Float) { + this.far = far - updateView() - } - - fun setFar(far: Float) { - this.far = far - - updateView() - } + updateView() + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/input/Input.kt b/src/main/kotlin/games/perses/input/Input.kt index 71a3adc..58c4f23 100644 --- a/src/main/kotlin/games/perses/input/Input.kt +++ b/src/main/kotlin/games/perses/input/Input.kt @@ -15,235 +15,235 @@ */ enum class KeyCode(val keyCode: Int) { - BACKSPACE(8), - TAB(9), - ENTER(13), - SHIFT(16), - CTRL(17), - ALT(18), - PAUSE_BREAK(19), - CAPS_LOCK(20), - ESCAPE(27), - SPACE(32), - PAGE_UP(33), - PAGE_DOWN(34), - END(35), - HOME(36), - LEFT_ARROW(37), - UP_ARROW(38), - RIGHT_ARROW(39), - DOWN_ARROW(40), - INSERT(45), - DELETE(46), - NR_0(48), - NR_1(49), - NR_2(50), - NR_3(51), - NR_4(52), - NR_5(53), - NR_6(54), - NR_7(55), - NR_8(56), - NR_9(57), - A(65), - B(66), - C(67), - D(68), - E(69), - F(70), - G(71), - H(72), - I(73), - J(74), - K(75), - L(76), - M(77), - N(78), - O(79), - P(80), - Q(81), - R(82), - S(83), - T(84), - U(85), - V(86), - W(87), - X(88), - Y(89), - Z(90), - LEFT_WINDOW_KEY(91), - RIGHT_WINDOW_KEY(92), - SELECT_KEY(93), - NUMPAD_0(96), - NUMPAD_1(97), - NUMPAD_2(98), - NUMPAD_3(99), - NUMPAD_4(100), - NUMPAD_5(101), - NUMPAD_6(102), - NUMPAD_7(103), - NUMPAD_8(104), - NUMPAD_9(105), - MULTIPLY(106), - ADD(107), - SUBTRACT(109), - DECIMAL_POINT(110), - DIVIDE(111), - F1(112), - F2(113), - F3(114), - F4(115), - F5(116), - F6(117), - F7(118), - F8(119), - F9(120), - F10(121), - F11(122), - F12(123), - NUM_LOCK(144), - SCROLL_LOCK(145), - SEMI_COLON(186), - EQUAL_SIGN(187), - COMMA(188), - DASH(189), - PERIOD(190), - FORWARD_SLASH(191), - GRAVE_ACCENT(192), - OPEN_BRACKET(219), - BACK_SLASH(220), - CLOSE_BRAKET(221), - SINGLE_QUOTE(222), + BACKSPACE(8), + TAB(9), + ENTER(13), + SHIFT(16), + CTRL(17), + ALT(18), + PAUSE_BREAK(19), + CAPS_LOCK(20), + ESCAPE(27), + SPACE(32), + PAGE_UP(33), + PAGE_DOWN(34), + END(35), + HOME(36), + LEFT_ARROW(37), + UP_ARROW(38), + RIGHT_ARROW(39), + DOWN_ARROW(40), + INSERT(45), + DELETE(46), + NR_0(48), + NR_1(49), + NR_2(50), + NR_3(51), + NR_4(52), + NR_5(53), + NR_6(54), + NR_7(55), + NR_8(56), + NR_9(57), + A(65), + B(66), + C(67), + D(68), + E(69), + F(70), + G(71), + H(72), + I(73), + J(74), + K(75), + L(76), + M(77), + N(78), + O(79), + P(80), + Q(81), + R(82), + S(83), + T(84), + U(85), + V(86), + W(87), + X(88), + Y(89), + Z(90), + LEFT_WINDOW_KEY(91), + RIGHT_WINDOW_KEY(92), + SELECT_KEY(93), + NUMPAD_0(96), + NUMPAD_1(97), + NUMPAD_2(98), + NUMPAD_3(99), + NUMPAD_4(100), + NUMPAD_5(101), + NUMPAD_6(102), + NUMPAD_7(103), + NUMPAD_8(104), + NUMPAD_9(105), + MULTIPLY(106), + ADD(107), + SUBTRACT(109), + DECIMAL_POINT(110), + DIVIDE(111), + F1(112), + F2(113), + F3(114), + F4(115), + F5(116), + F6(117), + F7(118), + F8(119), + F9(120), + F10(121), + F11(122), + F12(123), + NUM_LOCK(144), + SCROLL_LOCK(145), + SEMI_COLON(186), + EQUAL_SIGN(187), + COMMA(188), + DASH(189), + PERIOD(190), + FORWARD_SLASH(191), + GRAVE_ACCENT(192), + OPEN_BRACKET(219), + BACK_SLASH(220), + CLOSE_BRAKET(221), + SINGLE_QUOTE(222), - ESC(27), - LEFT(37), - UP(38), - DOWN(40), - RIGHT(39), - MINUS(109), - PLUS(107), + ESC(27), + LEFT(37), + UP(38), + DOWN(40), + RIGHT(39), + MINUS(109), + PLUS(107), } interface InputProcessor { - fun keyPressed(charCode: Int) + fun keyPressed(charCode: Int) - fun keyDown(keyCode: Int) + fun keyDown(keyCode: Int) - fun keyUp(keyCode: Int) + fun keyUp(keyCode: Int) - fun pointerClick(pointer: Int, x: Float, y: Float) + fun pointerClick(pointer: Int, x: Float, y: Float) - fun mouseMove(x: Float, y: Float) + fun mouseMove(x: Float, y: Float) } open class EmptyInputProcessor : InputProcessor { - override fun pointerClick(pointer: Int, x: Float, y: Float) { } + override fun pointerClick(pointer: Int, x: Float, y: Float) {} - override fun keyDown(keyCode: Int) { } + override fun keyDown(keyCode: Int) {} - override fun keyPressed(charCode: Int) { } + override fun keyPressed(charCode: Int) {} - override fun keyUp(keyCode: Int) { } + override fun keyUp(keyCode: Int) {} - override fun mouseMove(x: Float, y: Float) { } + override fun mouseMove(x: Float, y: Float) {} } object Input { - private val keys: MutableMap = HashMap() - private var inputProcesser: InputProcessor = EmptyInputProcessor() + private val keys: MutableMap = HashMap() + private var inputProcesser: InputProcessor = EmptyInputProcessor() - init { - val body = document.body - if (body != null) { - body.onkeydown = { - keyDown(it) - } + init { + val body = document.body + if (body != null) { + body.onkeydown = { + keyDown(it) + } - body.onkeyup = { - keyUp(it) - } + body.onkeyup = { + keyUp(it) + } - body.onkeypress = { - keyPress(it) - } + body.onkeypress = { + keyPress(it) + } - body.onclick = { - mouseClick(it) - } + body.onclick = { + mouseClick(it) + } - body.onmousedown = { - mouseMove(it) - } + body.onmousedown = { + mouseMove(it) + } - body.onmouseup = { - mouseMove(it) - } + body.onmouseup = { + mouseMove(it) + } - body.onmousemove = { - mouseMove(it) - } - } else { - console.log("Can't register key events, document.body is null!?") - } + body.onmousemove = { + mouseMove(it) + } + } else { + console.log("Can't register key events, document.body is null!?") } + } - fun setInputProcessor(processor: InputProcessor) { - this.inputProcesser = processor + fun setInputProcessor(processor: InputProcessor) { + this.inputProcesser = processor + } + + private fun keyDown(key: Event) { + if (key is KeyboardEvent) { + keys.put(key.keyCode, Date().getTime()) + + inputProcesser.keyDown(key.keyCode) } + } - private fun keyDown(key: Event) { - if (key is KeyboardEvent) { - keys.put(key.keyCode, Date().getTime()) + private fun keyUp(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyUp(key.keyCode) - inputProcesser.keyDown(key.keyCode) - } + keys.remove(key.keyCode) } + } - private fun keyUp(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyUp(key.keyCode) - - keys.remove(key.keyCode) - } + private fun keyPress(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyPressed(key.charCode) } + } - private fun keyPress(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyPressed(key.charCode) - } + private fun mouseClick(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + + inputProcesser.pointerClick(event.button.toInt(), vx, vy) } + } - private fun mouseClick(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + private fun mouseMove(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) - inputProcesser.pointerClick(event.button.toInt(), vx, vy) - } + inputProcesser.mouseMove(vx, vy) } + } - private fun mouseMove(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + fun isDown(keyCode: Int) = keys.containsKey(keyCode) - inputProcesser.mouseMove(vx, vy) - } - } + fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - fun isDown(keyCode: Int) = keys.containsKey(keyCode) + fun wasPressed(keyCode: Int, delta: Double): Boolean { + val time = keys[keyCode] - fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - - fun wasPressed(keyCode: Int, delta: Double): Boolean { - val time = keys[keyCode] - - return (time != null && time > (Date().getTime() - delta)) - } + return (time != null && time > (Date().getTime() - delta)) + } } diff --git a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt index f1c7808..f3d4126 100644 --- a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt +++ b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt @@ -11,201 +11,201 @@ */ class MapData { - var version: Int = 1 - var properties: MutableMap = HashMap() - var layers: Array? = null - var tilesets: Array? = null + var version: Int = 1 + var properties: MutableMap = HashMap() + var layers: Array? = null + var tilesets: Array? = null - var height: Int = 0 - var width: Int = 0 + var height: Int = 0 + var width: Int = 0 - var nextobjectid: Int = 0 - var orientation: String = "orthogonal" - var renderorder: String = "right-down" - var tileheight: Int = 0 - var tilewidth: Int = 0 + var nextobjectid: Int = 0 + var orientation: String = "orthogonal" + var renderorder: String = "right-down" + var tileheight: Int = 0 + var tilewidth: Int = 0 } class MapLayer { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var data: Array? = null - var encoding: String = "" - var x: Int = 0 - var y: Int = 0 - var width: Int = 0 - var height: Int = 0 - var name: String = "" - var opacity: Float = 1f - var type: String = "" - var visible: Boolean = true - var draworder: String = "" + var data: Array? = null + var encoding: String = "" + var x: Int = 0 + var y: Int = 0 + var width: Int = 0 + var height: Int = 0 + var name: String = "" + var opacity: Float = 1f + var type: String = "" + var visible: Boolean = true + var draworder: String = "" } class MapTileset { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var firstgid: Int = 0 - var image: String = "" - var imageheight: Int = 0 - var imagewidth: Int = 0 - var margin: Int = 0 - var name: String = "" - var spacing: Int = 0 - var tilecount: Int = 0 - var tileheight: Int = 0 - var tilewidth: Int = 0 - var tileproperties: MutableMap> = HashMap() + var firstgid: Int = 0 + var image: String = "" + var imageheight: Int = 0 + var imagewidth: Int = 0 + var margin: Int = 0 + var name: String = "" + var spacing: Int = 0 + var tilecount: Int = 0 + var tileheight: Int = 0 + var tilewidth: Int = 0 + var tileproperties: MutableMap> = HashMap() } class TilesetIndex( - val texture: Texture?, - val tcLeft: Float, - val tcTop: Float, - val tcRight: Float, - val tcBottom: Float, - val scale: Float - ) { - constructor() : this(null, 0f, 0f, 0f, 0f, 0f) + val texture: Texture?, + val tcLeft: Float, + val tcTop: Float, + val tcRight: Float, + val tcBottom: Float, + val scale: Float +) { + constructor() : this(null, 0f, 0f, 0f, 0f, 0f) - fun render(x: Float, y: Float) { - texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) - } + fun render(x: Float, y: Float) { + texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) + } } class TiledMap(dir: String = "", url: String) { - val properties: Map = HashMap() - val data: MapData - val tileset: Array - val tiles: Array - var first = true - //var tilesetIndex: Array = Array(0, { TilesetIndex() }) + val properties: Map = HashMap() + val data: MapData + val tileset: Array + val tiles: Array + var first = true + //var tilesetIndex: Array = Array(0, { TilesetIndex() }) - init { - var tileDir = dir - if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { - tileDir = tileDir + "/" - } - - data = JSON.parse(getUrlAsString(tileDir + url)) - //println("map data is loaded") - val tilesets = data.tilesets - if (tilesets != null) { - tileset = Array(tilesets.size, { "" }) - var maxGid = 0 - for (index in 0..tilesets.size - 1) { - tileset[index] = tilesets[index].name - Textures.load(tilesets[index].name, tileDir + tilesets[index].image) - maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) - } - - tiles = Array(maxGid, { TilesetIndex() }) - } else { - tileset = Array(0, { "" }) - tiles = Array(0, { TilesetIndex() }) - } - - cacheTiles() + init { + var tileDir = dir + if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { + tileDir = tileDir + "/" } - fun cacheTiles() { - if (!Textures.ready()) { - window.setTimeout({ cacheTiles() }, 10) - } else { - val tilesets = data.tilesets - var tcLeft = 0f - var tcTop = 0f - var tcRight = 0f - var tcBottom = 0f + data = JSON.parse(getUrlAsString(tileDir + url)) + //println("map data is loaded") + val tilesets = data.tilesets + if (tilesets != null) { + tileset = Array(tilesets.size, { "" }) + var maxGid = 0 + for (index in 0..tilesets.size - 1) { + tileset[index] = tilesets[index].name + Textures.load(tilesets[index].name, tileDir + tilesets[index].image) + maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) + } - if (tilesets != null) { - - - for (tileset in tilesets) { - val tilesHor = tileset.imagewidth / tileset.tilewidth - val tilesVer = tileset.imageheight / tileset.tileheight - val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) - - for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { - val texture = Textures.get(tileset.name) - - val gid = index - tileset.firstgid - - val xi = gid % tilesHor - var yi = gid / tilesHor - yi = tilesVer - yi - 1 - val tw = 1f / tilesHor.toFloat() - val th = 1f / tilesVer.toFloat() - - val pixelW = 0.1f / tileset.tilewidth - val pixelH = 0.1f / tileset.tileheight - - tcLeft = xi * tw - tcRight = tcLeft + tw - - // switch up/down because of texture coord 0,0 in left bottom corner - tcBottom = yi * th - tcTop = tcBottom + th - - tcLeft += pixelW - tcRight -= pixelW - - tcBottom += pixelH - tcTop -= pixelH - - tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) - } - } - } - } + tiles = Array(maxGid, { TilesetIndex() }) + } else { + tileset = Array(0, { "" }) + tiles = Array(0, { TilesetIndex() }) } - fun drawTile(tile: Int, x: Float, y: Float) { - tiles[tile].render(x, y) + cacheTiles() + } + + fun cacheTiles() { + if (!Textures.ready()) { + window.setTimeout({ cacheTiles() }, 10) + } else { + val tilesets = data.tilesets + var tcLeft = 0f + var tcTop = 0f + var tcRight = 0f + var tcBottom = 0f + + if (tilesets != null) { + + + for (tileset in tilesets) { + val tilesHor = tileset.imagewidth / tileset.tilewidth + val tilesVer = tileset.imageheight / tileset.tileheight + val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) + + for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { + val texture = Textures.get(tileset.name) + + val gid = index - tileset.firstgid + + val xi = gid % tilesHor + var yi = gid / tilesHor + yi = tilesVer - yi - 1 + val tw = 1f / tilesHor.toFloat() + val th = 1f / tilesVer.toFloat() + + val pixelW = 0.1f / tileset.tilewidth + val pixelH = 0.1f / tileset.tileheight + + tcLeft = xi * tw + tcRight = tcLeft + tw + + // switch up/down because of texture coord 0,0 in left bottom corner + tcBottom = yi * th + tcTop = tcBottom + th + + tcLeft += pixelW + tcRight -= pixelW + + tcBottom += pixelH + tcTop -= pixelH + + tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) + } + } + } + } + } + + fun drawTile(tile: Int, x: Float, y: Float) { + tiles[tile].render(x, y) + } + + fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { + var x = 0f + var y = 0f + val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") + val layer = layers[layerIndex] + + val layerData = layer.data + if (layerData != null) { + for (index in layerData.indices) { + // todo: determine if in view + // todo: determine tilewidth + //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { + drawTile(layerData[index], xo + x * 128f, yo + y * 128f) + + when (data.renderorder) { + "right-down" -> { + x++ + if (x >= layer.width) { + x = 0f + y-- + } + } + else -> { + throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") + } + } + //} + } } - fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { - var x = 0f - var y = 0f - val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") - val layer = layers[layerIndex] + val tilesets = data.tilesets + if (tilesets != null) { + for (tileset in tilesets) { + if (Textures.has(tileset.name)) { + val tx = Textures.get(tileset.name) - val layerData = layer.data - if (layerData != null) { - for (index in layerData.indices) { - // todo: determine if in view - // todo: determine tilewidth - //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { - drawTile(layerData[index], xo + x * 128f, yo + y * 128f) - - when (data.renderorder) { - "right-down" -> { - x++ - if (x >= layer.width) { - x = 0f - y-- - } - } - else -> { - throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") - } - } - //} - } + tx.render() } - - val tilesets = data.tilesets - if (tilesets != null) { - for (tileset in tilesets) { - if (Textures.has(tileset.name)) { - val tx = Textures.get(tileset.name) - - tx.render() - } - } - } - - - first = false + } } + + + first = false + } } diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml index 43edcc2..7ed1494 100644 --- a/.idea/modules/kudens_test.iml +++ b/.idea/modules/kudens_test.iml @@ -1,8 +1,9 @@ - + + $MODULE_DIR$/../../build/kotlinjs/kudens.js \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7ae9969..e7225a0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'perses.games' -version '1.1.6-SNAPSHOT' +version '1.1.7-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'idea' @@ -20,7 +20,7 @@ } buildscript { - ext.kotlin_version = '1.2.21' + ext.kotlin_version = '1.2.30' repositories { maven { url "http://nexus.astraeus.nl/nexus/content/groups/public" diff --git a/src/main/kotlin/games/perses/color/Color.kt b/src/main/kotlin/games/perses/color/Color.kt index 7f235b0..31b540f 100644 --- a/src/main/kotlin/games/perses/color/Color.kt +++ b/src/main/kotlin/games/perses/color/Color.kt @@ -10,107 +10,107 @@ object Color { - /** - * Converts an HSL color value to RGB. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes h, s, and l are contained in the set [0, 1] and - * returns r, g, and b in the set [0, 255]. + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. - * @param h The hue - * * - * @param s The saturation - * * - * @param l The lightness - * * - * @return int array, the RGB representation - */ - fun hslToRgb(h: Float, s: Float, l: Float): IntArray { - val r: Float - val g: Float - val b: Float + * @param h The hue + * * + * @param s The saturation + * * + * @param l The lightness + * * + * @return int array, the RGB representation + */ + fun hslToRgb(h: Float, s: Float, l: Float): IntArray { + val r: Float + val g: Float + val b: Float - if (s == 0f) { - b = l - g = b - r = g // achromatic - } else { - val q = if (l < 0.5f) l * (1 + s) else l + s - l * s - val p = 2 * l - q - r = hueToRgb(p, q, h + 1f / 3f) - g = hueToRgb(p, q, h) - b = hueToRgb(p, q, h - 1f / 3f) - } - val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) + if (s == 0f) { + b = l + g = b + r = g // achromatic + } else { + val q = if (l < 0.5f) l * (1 + s) else l + s - l * s + val p = 2 * l - q + r = hueToRgb(p, q, h + 1f / 3f) + g = hueToRgb(p, q, h) + b = hueToRgb(p, q, h - 1f / 3f) + } + val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) - return rgb + return rgb + } + + /** Helper method that converts hue to rgb */ + fun hueToRgb(p: Float, q: Float, t: Float): Float { + var lt = t + if (lt < 0f) { + lt += 1f + } + if (lt > 1f) { + lt -= 1f + } + if (lt < 1f / 6f) { + return p + (q - p) * 6f * lt + } + if (lt < 1f / 2f) { + return q + } + if (lt < 2f / 3f) { + return p + (q - p) * (2f / 3f - lt) * 6f + } + return p + } + + /** + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes pR, pG, and bpBare contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + + * @param pR The red color value + * * + * @param pG The green color value + * * + * @param pB The blue color value + * * + * @return float array, the HSL representation + */ + fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { + val r = pR / 255f + val g = pG / 255f + val b = pB / 255f + + val max = if (r > g && r > b) r else if (g > b) g else b + val min = if (r < g && r < b) r else if (g < b) g else b + + var h: Float + val s: Float + val l: Float + l = (max + min) / 2.0f + + if (max == min) { + s = 0.0f + h = s + } else { + val d = max - min + s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) + + if (r > g && r > b) + h = (g - b) / d + (if (g < b) 6.0f else 0.0f) + else if (g > b) + h = (b - r) / d + 2.0f + else + h = (r - g) / d + 4.0f + + h /= 6.0f } - /** Helper method that converts hue to rgb */ - fun hueToRgb(p: Float, q: Float, t: Float): Float { - var lt = t - if (lt < 0f) { - lt += 1f - } - if (lt > 1f) { - lt -= 1f - } - if (lt < 1f / 6f) { - return p + (q - p) * 6f * lt - } - if (lt < 1f / 2f) { - return q - } - if (lt < 2f / 3f) { - return p + (q - p) * (2f / 3f - lt) * 6f - } - return p - } - - /** - * Converts an RGB color value to HSL. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes pR, pG, and bpBare contained in the set [0, 255] and - * returns h, s, and l in the set [0, 1]. - - * @param pR The red color value - * * - * @param pG The green color value - * * - * @param pB The blue color value - * * - * @return float array, the HSL representation - */ - fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { - val r = pR / 255f - val g = pG / 255f - val b = pB / 255f - - val max = if (r > g && r > b) r else if (g > b) g else b - val min = if (r < g && r < b) r else if (g < b) g else b - - var h: Float - val s: Float - val l: Float - l = (max + min) / 2.0f - - if (max == min) { - s = 0.0f - h = s - } else { - val d = max - min - s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) - - if (r > g && r > b) - h = (g - b) / d + (if (g < b) 6.0f else 0.0f) - else if (g > b) - h = (b - r) / d + 2.0f - else - h = (r - g) / d + 4.0f - - h /= 6.0f - } - - val hsl = floatArrayOf(h, s, l) - return hsl - } + val hsl = floatArrayOf(h, s, l) + return hsl + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/game/Game.kt b/src/main/kotlin/games/perses/game/Game.kt index 0961316..1becee5 100644 --- a/src/main/kotlin/games/perses/game/Game.kt +++ b/src/main/kotlin/games/perses/game/Game.kt @@ -14,210 +14,210 @@ */ enum class DrawMode { - LINEAR, - NEAREST + LINEAR, + NEAREST } class HTMLElements { - var container: HTMLElement - var webgl: WebGLRenderingContext - var canvas2d: CanvasRenderingContext2D + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D - init { - container = document.createElement("div") as HTMLElement + init { + container = document.createElement("div") as HTMLElement - val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement - val canvas = document.createElement("canvas") as HTMLCanvasElement + val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + val canvas = document.createElement("canvas") as HTMLCanvasElement - container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") - webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" ) - canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" ) + container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;") - document.body!!.appendChild(container) - container.appendChild(webGlCanvas) - container.appendChild(canvas) + document.body!!.appendChild(container) + container.appendChild(webGlCanvas) + container.appendChild(canvas) - val canvas2dcanvas = canvas.getContext("2d") + val canvas2dcanvas = canvas.getContext("2d") - var webglcanvas = webGlCanvas.getContext("webgl") - if (webglcanvas == null) { - console.log("webgl context not found, trying experimental-webgl.") - webglcanvas = webGlCanvas.getContext("experimental-webgl") - } - - if (webglcanvas != null) { - webgl = webglcanvas as WebGLRenderingContext - } else { - console.log("webgl?", webglcanvas) - window.alert("Your browser doesn't seem to support webgl!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } - - if (canvas2dcanvas != null) { - canvas2d = canvas2dcanvas as CanvasRenderingContext2D - } else { - console.log("canvas2d?", canvas2dcanvas) - window.alert("Your browser doesn't seem to support 2d canvas!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } + var webglcanvas = webGlCanvas.getContext("webgl") + if (webglcanvas == null) { + console.log("webgl context not found, trying experimental-webgl.") + webglcanvas = webGlCanvas.getContext("experimental-webgl") } + + if (webglcanvas != null) { + webgl = webglcanvas as WebGLRenderingContext + } else { + console.log("webgl?", webglcanvas) + window.alert("Your browser doesn't seem to support webgl!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + + if (canvas2dcanvas != null) { + canvas2d = canvas2dcanvas as CanvasRenderingContext2D + } else { + console.log("canvas2d?", canvas2dcanvas) + window.alert("Your browser doesn't seem to support 2d canvas!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + } } object Game { - var started = false - val view: View = View() - val html: HTMLElements by lazy { HTMLElements() } - var currentScreen: Screen = DefaultScreen() - var start = Date().getTime() - var currentTime = start - var currentDelta = 0f - var pause: Boolean = false - var clearScreenEveryFrame = true + var started = false + val view: View = View() + val html: HTMLElements by lazy { HTMLElements() } + var currentScreen: Screen = DefaultScreen() + var start = Date().getTime() + var currentTime = start + var currentDelta = 0f + var pause: Boolean = false + var clearScreenEveryFrame = true - var clearRed = 0f - var clearGreen = 0f - var clearBlue = 0f - var clearAlpha = 1f + var clearRed = 0f + var clearGreen = 0f + var clearBlue = 0f + var clearAlpha = 1f - var fps = 0 - var fpsCount = 0 - var fpsCountTime = 0f + var fps = 0 + var fpsCount = 0 + var fpsCountTime = 0f - var borderLeft = 0 - var borderTop = 0 + var borderLeft = 0 + var borderTop = 0 - var focus = true + var focus = true - init { - window.onfocus = { - //println("GOT FOCUS!") + init { + window.onfocus = { + //println("GOT FOCUS!") - focus = true - "" - } - window.onblur = { - //println("LOST FOCUS!") + focus = true + "" + } + window.onblur = { + //println("LOST FOCUS!") - focus = false - "" - } - + focus = false + "" } - fun gl() = html.webgl + } - fun resize() { - val canvas = gl().canvas + fun gl() = html.webgl - // Check if the canvas is not the same size. - val windowWidth = window.innerWidth.toInt() - val windowHeight = window.innerHeight.toInt() + fun resize() { + val canvas = gl().canvas - if (view.lastWindowWidth != windowWidth || - view.lastWindowHeight != windowHeight) { - view.lastWindowWidth = windowWidth - view.lastWindowHeight = windowHeight - view.windowWidth = windowWidth - view.windowHeight = windowHeight + // Check if the canvas is not the same size. + val windowWidth = window.innerWidth.toInt() + val windowHeight = window.innerHeight.toInt() - view.updateView() + if (view.lastWindowWidth != windowWidth || + view.lastWindowHeight != windowHeight) { + view.lastWindowWidth = windowWidth + view.lastWindowHeight = windowHeight + view.windowWidth = windowWidth + view.windowHeight = windowHeight - val textCanvas = html.canvas2d.canvas + view.updateView() - // Make the canvas the same size - canvas.width = view.width.toInt() - canvas.height = view.height.toInt() + val textCanvas = html.canvas2d.canvas - textCanvas.width = view.width.toInt() - textCanvas.height = view.height.toInt() + // Make the canvas the same size + canvas.width = view.width.toInt() + canvas.height = view.height.toInt() - gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) + textCanvas.width = view.width.toInt() + textCanvas.height = view.height.toInt() - borderLeft = (windowWidth - view.windowWidth) / 2 - borderTop = (windowHeight - view.windowHeight) / 2 + gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) - canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) - textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) + borderLeft = (windowWidth - view.windowWidth) / 2 + borderTop = (windowHeight - view.windowHeight) / 2 + + canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + } + } + + fun start(startScreen: Screen) { + if (started) { + throw IllegalStateException("You can only start a game once!") + } + + setScreen(startScreen) + + // start game loop + started = true + gameLoop() + } + + fun setScreen(screen: Screen) { + currentScreen.unloadResources() + + currentScreen = screen + + screen.loadResources() + } + + fun setClearColor(r: Float, g: Float, b: Float, a: Float) { + clearRed = r + clearGreen = g + clearBlue = b + clearAlpha = a + } + + fun gameLoop() { + try { + if (!Textures.ready()) { + gl().clearColor(1f, 1f, 1f, 1f) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } else { + resize() + + if (!pause) { + html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); + + if (clearScreenEveryFrame) { + gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } + + gl().enable(WebGLRenderingContext.BLEND) + gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); + + val time = Date().getTime() + currentDelta = ((time - currentTime) / 1000f).toFloat() + currentTime = time + + val timeInSeconds = (currentTime - start) / 1000f + + fpsCountTime += currentDelta + fpsCount++ + while (fpsCountTime > 1f) { + fps = fpsCount + fpsCountTime -= 1f + fpsCount = 0 + } + + if (focus) { + currentScreen.update(timeInSeconds.toFloat(), currentDelta) + } + + currentScreen.render() } + } + } catch (e: Exception) { + println("Some error...") + console.log(e) } - fun start(startScreen: Screen) { - if (started) { - throw IllegalStateException("You can only start a game once!") - } - - setScreen(startScreen) - - // start game loop - started = true - gameLoop() + window.requestAnimationFrame { + gameLoop() } - - fun setScreen(screen: Screen) { - currentScreen.unloadResources() - - currentScreen = screen - - screen.loadResources() - } - - fun setClearColor(r: Float, g: Float, b: Float, a: Float) { - clearRed = r - clearGreen = g - clearBlue = b - clearAlpha = a - } - - fun gameLoop() { - try { - if (!Textures.ready()) { - gl().clearColor(1f, 1f, 1f, 1f) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } else { - resize() - - if (!pause) { - html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); - - if (clearScreenEveryFrame) { - gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } - - gl().enable(WebGLRenderingContext.BLEND) - gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); - - val time = Date().getTime() - currentDelta = ((time - currentTime) / 1000f).toFloat() - currentTime = time - - val timeInSeconds = (currentTime - start) / 1000f - - fpsCountTime += currentDelta - fpsCount++ - while (fpsCountTime > 1f) { - fps = fpsCount - fpsCountTime -= 1f - fpsCount = 0 - } - - if (focus) { - currentScreen.update(timeInSeconds.toFloat(), currentDelta) - } - - currentScreen.render() - } - } - } catch(e: Exception) { - println("Some error...") - console.log(e) - } - - window.requestAnimationFrame { - gameLoop() - } - } + } } diff --git a/src/main/kotlin/games/perses/game/Screen.kt b/src/main/kotlin/games/perses/game/Screen.kt index 10b6eae..7b381e7 100644 --- a/src/main/kotlin/games/perses/game/Screen.kt +++ b/src/main/kotlin/games/perses/game/Screen.kt @@ -8,31 +8,31 @@ abstract class Screen { - open fun loadResources() {} + open fun loadResources() {} - @Deprecated( + @Deprecated( message = "replace with unloadResources", replaceWith = ReplaceWith("unloadResources()") - ) - open fun closeResources() { - unloadResources() - } + ) + open fun closeResources() { + unloadResources() + } - open fun unloadResources() {} + open fun unloadResources() {} - abstract fun update(time: Float, delta: Float) + abstract fun update(time: Float, delta: Float) - abstract fun render() + abstract fun render() } -class DefaultScreen: Screen() { - override fun update(time: Float, delta: Float) { - } +class DefaultScreen : Screen() { + override fun update(time: Float, delta: Float) { + } - override fun render() { - // show loading message? - Game.gl().clearColor(1f, 1f, 0f, 1f) - Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } + override fun render() { + // show loading message? + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } } diff --git a/src/main/kotlin/games/perses/game/View.kt b/src/main/kotlin/games/perses/game/View.kt index 540a44d..16c9913 100644 --- a/src/main/kotlin/games/perses/game/View.kt +++ b/src/main/kotlin/games/perses/game/View.kt @@ -4,39 +4,39 @@ import kotlin.browser.document enum class ViewType { - PROJECTION, - WIDTH, - HEIGHT, - ABSOLUTE + PROJECTION, + WIDTH, + HEIGHT, + ABSOLUTE } class View( - var lastWindowWidth: Int = 2000, - var lastWindowHeight: Int = 1000, - var windowWidth: Int = 2000, - var windowHeight: Int = 1000, - var width: Float = 1024f, - var height: Float = 1024f, - var angle: Float = 60f, - var near: Float = -0.1f, - var far: Float = -100f, - var minAspectRatio: Float = 1f, - var maxAspectRatio: Float = 1f, - var leftOffset: Int = 0, - var bottomOffset: Int = 0, - var viewType: ViewType = ViewType.WIDTH, - var drawMode: DrawMode = DrawMode.LINEAR) { - var vMatrix = Matrix4() - var aspectRatio = 1f + var lastWindowWidth: Int = 2000, + var lastWindowHeight: Int = 1000, + var windowWidth: Int = 2000, + var windowHeight: Int = 1000, + var width: Float = 1024f, + var height: Float = 1024f, + var angle: Float = 60f, + var near: Float = -0.1f, + var far: Float = -100f, + var minAspectRatio: Float = 1f, + var maxAspectRatio: Float = 1f, + var leftOffset: Int = 0, + var bottomOffset: Int = 0, + var viewType: ViewType = ViewType.WIDTH, + var drawMode: DrawMode = DrawMode.LINEAR) { + var vMatrix = Matrix4() + var aspectRatio = 1f - init { - updateView() - } + init { + updateView() + } - fun requestFullscreen() { - val element = document.body - //language=javascript - js(""" + fun requestFullscreen() { + val element = document.body + //language=javascript + js(""" if(element.requestFullscreen) { element.requestFullscreen(); } else if(element.mozRequestFullScreen) { @@ -47,10 +47,10 @@ element.msRequestFullscreen(); } """) - } + } - fun exitFullscreen() { - js(""" + fun exitFullscreen() { + js(""" if(document.exitFullscreen) { document.exitFullscreen(); } else if(document.mozCancelFullScreen) { @@ -59,178 +59,178 @@ document.webkitExitFullscreen(); } """) + } + + fun switchFullscreen() { + if (isFullscreen()) { + exitFullscreen() + } else { + requestFullscreen() + } + } + + fun isFullscreen(): Boolean { + val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + + return fse != undefined + } + + fun updateView() { + aspectRatio = windowWidth / windowHeight.toFloat() + + if (aspectRatio < minAspectRatio) { + aspectRatio = minAspectRatio + + windowHeight = (windowWidth / aspectRatio).toInt() } - fun switchFullscreen() { - if (isFullscreen()) { - exitFullscreen() - } else { - requestFullscreen() - } + if (aspectRatio > maxAspectRatio) { + aspectRatio = maxAspectRatio + + windowWidth = (windowHeight * aspectRatio).toInt() } - fun isFullscreen(): Boolean { - val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + when (viewType) { + ViewType.ABSOLUTE -> { + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.WIDTH -> { + height = width / aspectRatio - return fse != undefined + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.HEIGHT -> { + width = height * aspectRatio + + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.PROJECTION -> { + vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun updateView() { - aspectRatio = windowWidth / windowHeight.toFloat() + //println("width: $width, height: $height") + } - if (aspectRatio < minAspectRatio) { - aspectRatio = minAspectRatio + fun screenToGameCoordX(screenX: Float): Float { + var result = screenX - windowHeight = (windowWidth / aspectRatio).toInt() - } - - if (aspectRatio > maxAspectRatio) { - aspectRatio = maxAspectRatio - - windowWidth = (windowHeight * aspectRatio).toInt() - } - - when (viewType) { - ViewType.ABSOLUTE -> { - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.WIDTH -> { - height = width / aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.HEIGHT -> { - width = height * aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.PROJECTION -> { - vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } - - //println("width: $width, height: $height") + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = ((screenX - Game.borderLeft) * width / windowWidth) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordX(screenX: Float): Float { - var result = screenX + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( (screenX - Game.borderLeft) * width / windowWidth ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun screenToGameCoordY(screenY: Float): Float { + var result = screenY - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - ((screenY - Game.borderTop) * height / windowHeight) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordY(screenY: Float): Float { - var result = screenY + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( (screenY - Game.borderTop) * height / windowHeight ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordX(gameX: Float): Float { + var result = gameX + val normalizedX = gameX + (width / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = (gameX / width * windowWidth) + Game.borderLeft + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordX(gameX: Float): Float { - var result = gameX - val normalizedX = gameX + (width / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( gameX / width * windowWidth ) + Game.borderLeft - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordY(gameY: Float): Float { + var result = gameY + val normalizedY = gameY + (height / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - (gameY / height * windowHeight) + Game.borderTop + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordY(gameY: Float): Float { - var result = gameY - val normalizedY = gameY + (height / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( gameY / height * windowHeight ) + Game.borderTop - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun setToWidth(width: Float) { + this.width = width + this.viewType = ViewType.WIDTH - return result - } + updateView() + } - fun setToWidth(width: Float) { - this.width = width - this.viewType = ViewType.WIDTH + fun setToHeight(height: Float) { + this.height = height + this.viewType = ViewType.HEIGHT - updateView() - } + updateView() + } - fun setToHeight(height: Float) { - this.height = height - this.viewType = ViewType.HEIGHT + fun setProjection(angle: Float) { + this.angle = angle + this.viewType = ViewType.PROJECTION - updateView() - } + updateView() + } - fun setProjection(angle: Float) { - this.angle = angle - this.viewType = ViewType.PROJECTION + fun setNear(near: Float) { + this.near = near - updateView() - } + updateView() + } - fun setNear(near: Float) { - this.near = near + fun setFar(far: Float) { + this.far = far - updateView() - } - - fun setFar(far: Float) { - this.far = far - - updateView() - } + updateView() + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/input/Input.kt b/src/main/kotlin/games/perses/input/Input.kt index 71a3adc..58c4f23 100644 --- a/src/main/kotlin/games/perses/input/Input.kt +++ b/src/main/kotlin/games/perses/input/Input.kt @@ -15,235 +15,235 @@ */ enum class KeyCode(val keyCode: Int) { - BACKSPACE(8), - TAB(9), - ENTER(13), - SHIFT(16), - CTRL(17), - ALT(18), - PAUSE_BREAK(19), - CAPS_LOCK(20), - ESCAPE(27), - SPACE(32), - PAGE_UP(33), - PAGE_DOWN(34), - END(35), - HOME(36), - LEFT_ARROW(37), - UP_ARROW(38), - RIGHT_ARROW(39), - DOWN_ARROW(40), - INSERT(45), - DELETE(46), - NR_0(48), - NR_1(49), - NR_2(50), - NR_3(51), - NR_4(52), - NR_5(53), - NR_6(54), - NR_7(55), - NR_8(56), - NR_9(57), - A(65), - B(66), - C(67), - D(68), - E(69), - F(70), - G(71), - H(72), - I(73), - J(74), - K(75), - L(76), - M(77), - N(78), - O(79), - P(80), - Q(81), - R(82), - S(83), - T(84), - U(85), - V(86), - W(87), - X(88), - Y(89), - Z(90), - LEFT_WINDOW_KEY(91), - RIGHT_WINDOW_KEY(92), - SELECT_KEY(93), - NUMPAD_0(96), - NUMPAD_1(97), - NUMPAD_2(98), - NUMPAD_3(99), - NUMPAD_4(100), - NUMPAD_5(101), - NUMPAD_6(102), - NUMPAD_7(103), - NUMPAD_8(104), - NUMPAD_9(105), - MULTIPLY(106), - ADD(107), - SUBTRACT(109), - DECIMAL_POINT(110), - DIVIDE(111), - F1(112), - F2(113), - F3(114), - F4(115), - F5(116), - F6(117), - F7(118), - F8(119), - F9(120), - F10(121), - F11(122), - F12(123), - NUM_LOCK(144), - SCROLL_LOCK(145), - SEMI_COLON(186), - EQUAL_SIGN(187), - COMMA(188), - DASH(189), - PERIOD(190), - FORWARD_SLASH(191), - GRAVE_ACCENT(192), - OPEN_BRACKET(219), - BACK_SLASH(220), - CLOSE_BRAKET(221), - SINGLE_QUOTE(222), + BACKSPACE(8), + TAB(9), + ENTER(13), + SHIFT(16), + CTRL(17), + ALT(18), + PAUSE_BREAK(19), + CAPS_LOCK(20), + ESCAPE(27), + SPACE(32), + PAGE_UP(33), + PAGE_DOWN(34), + END(35), + HOME(36), + LEFT_ARROW(37), + UP_ARROW(38), + RIGHT_ARROW(39), + DOWN_ARROW(40), + INSERT(45), + DELETE(46), + NR_0(48), + NR_1(49), + NR_2(50), + NR_3(51), + NR_4(52), + NR_5(53), + NR_6(54), + NR_7(55), + NR_8(56), + NR_9(57), + A(65), + B(66), + C(67), + D(68), + E(69), + F(70), + G(71), + H(72), + I(73), + J(74), + K(75), + L(76), + M(77), + N(78), + O(79), + P(80), + Q(81), + R(82), + S(83), + T(84), + U(85), + V(86), + W(87), + X(88), + Y(89), + Z(90), + LEFT_WINDOW_KEY(91), + RIGHT_WINDOW_KEY(92), + SELECT_KEY(93), + NUMPAD_0(96), + NUMPAD_1(97), + NUMPAD_2(98), + NUMPAD_3(99), + NUMPAD_4(100), + NUMPAD_5(101), + NUMPAD_6(102), + NUMPAD_7(103), + NUMPAD_8(104), + NUMPAD_9(105), + MULTIPLY(106), + ADD(107), + SUBTRACT(109), + DECIMAL_POINT(110), + DIVIDE(111), + F1(112), + F2(113), + F3(114), + F4(115), + F5(116), + F6(117), + F7(118), + F8(119), + F9(120), + F10(121), + F11(122), + F12(123), + NUM_LOCK(144), + SCROLL_LOCK(145), + SEMI_COLON(186), + EQUAL_SIGN(187), + COMMA(188), + DASH(189), + PERIOD(190), + FORWARD_SLASH(191), + GRAVE_ACCENT(192), + OPEN_BRACKET(219), + BACK_SLASH(220), + CLOSE_BRAKET(221), + SINGLE_QUOTE(222), - ESC(27), - LEFT(37), - UP(38), - DOWN(40), - RIGHT(39), - MINUS(109), - PLUS(107), + ESC(27), + LEFT(37), + UP(38), + DOWN(40), + RIGHT(39), + MINUS(109), + PLUS(107), } interface InputProcessor { - fun keyPressed(charCode: Int) + fun keyPressed(charCode: Int) - fun keyDown(keyCode: Int) + fun keyDown(keyCode: Int) - fun keyUp(keyCode: Int) + fun keyUp(keyCode: Int) - fun pointerClick(pointer: Int, x: Float, y: Float) + fun pointerClick(pointer: Int, x: Float, y: Float) - fun mouseMove(x: Float, y: Float) + fun mouseMove(x: Float, y: Float) } open class EmptyInputProcessor : InputProcessor { - override fun pointerClick(pointer: Int, x: Float, y: Float) { } + override fun pointerClick(pointer: Int, x: Float, y: Float) {} - override fun keyDown(keyCode: Int) { } + override fun keyDown(keyCode: Int) {} - override fun keyPressed(charCode: Int) { } + override fun keyPressed(charCode: Int) {} - override fun keyUp(keyCode: Int) { } + override fun keyUp(keyCode: Int) {} - override fun mouseMove(x: Float, y: Float) { } + override fun mouseMove(x: Float, y: Float) {} } object Input { - private val keys: MutableMap = HashMap() - private var inputProcesser: InputProcessor = EmptyInputProcessor() + private val keys: MutableMap = HashMap() + private var inputProcesser: InputProcessor = EmptyInputProcessor() - init { - val body = document.body - if (body != null) { - body.onkeydown = { - keyDown(it) - } + init { + val body = document.body + if (body != null) { + body.onkeydown = { + keyDown(it) + } - body.onkeyup = { - keyUp(it) - } + body.onkeyup = { + keyUp(it) + } - body.onkeypress = { - keyPress(it) - } + body.onkeypress = { + keyPress(it) + } - body.onclick = { - mouseClick(it) - } + body.onclick = { + mouseClick(it) + } - body.onmousedown = { - mouseMove(it) - } + body.onmousedown = { + mouseMove(it) + } - body.onmouseup = { - mouseMove(it) - } + body.onmouseup = { + mouseMove(it) + } - body.onmousemove = { - mouseMove(it) - } - } else { - console.log("Can't register key events, document.body is null!?") - } + body.onmousemove = { + mouseMove(it) + } + } else { + console.log("Can't register key events, document.body is null!?") } + } - fun setInputProcessor(processor: InputProcessor) { - this.inputProcesser = processor + fun setInputProcessor(processor: InputProcessor) { + this.inputProcesser = processor + } + + private fun keyDown(key: Event) { + if (key is KeyboardEvent) { + keys.put(key.keyCode, Date().getTime()) + + inputProcesser.keyDown(key.keyCode) } + } - private fun keyDown(key: Event) { - if (key is KeyboardEvent) { - keys.put(key.keyCode, Date().getTime()) + private fun keyUp(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyUp(key.keyCode) - inputProcesser.keyDown(key.keyCode) - } + keys.remove(key.keyCode) } + } - private fun keyUp(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyUp(key.keyCode) - - keys.remove(key.keyCode) - } + private fun keyPress(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyPressed(key.charCode) } + } - private fun keyPress(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyPressed(key.charCode) - } + private fun mouseClick(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + + inputProcesser.pointerClick(event.button.toInt(), vx, vy) } + } - private fun mouseClick(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + private fun mouseMove(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) - inputProcesser.pointerClick(event.button.toInt(), vx, vy) - } + inputProcesser.mouseMove(vx, vy) } + } - private fun mouseMove(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + fun isDown(keyCode: Int) = keys.containsKey(keyCode) - inputProcesser.mouseMove(vx, vy) - } - } + fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - fun isDown(keyCode: Int) = keys.containsKey(keyCode) + fun wasPressed(keyCode: Int, delta: Double): Boolean { + val time = keys[keyCode] - fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - - fun wasPressed(keyCode: Int, delta: Double): Boolean { - val time = keys[keyCode] - - return (time != null && time > (Date().getTime() - delta)) - } + return (time != null && time > (Date().getTime() - delta)) + } } diff --git a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt index f1c7808..f3d4126 100644 --- a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt +++ b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt @@ -11,201 +11,201 @@ */ class MapData { - var version: Int = 1 - var properties: MutableMap = HashMap() - var layers: Array? = null - var tilesets: Array? = null + var version: Int = 1 + var properties: MutableMap = HashMap() + var layers: Array? = null + var tilesets: Array? = null - var height: Int = 0 - var width: Int = 0 + var height: Int = 0 + var width: Int = 0 - var nextobjectid: Int = 0 - var orientation: String = "orthogonal" - var renderorder: String = "right-down" - var tileheight: Int = 0 - var tilewidth: Int = 0 + var nextobjectid: Int = 0 + var orientation: String = "orthogonal" + var renderorder: String = "right-down" + var tileheight: Int = 0 + var tilewidth: Int = 0 } class MapLayer { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var data: Array? = null - var encoding: String = "" - var x: Int = 0 - var y: Int = 0 - var width: Int = 0 - var height: Int = 0 - var name: String = "" - var opacity: Float = 1f - var type: String = "" - var visible: Boolean = true - var draworder: String = "" + var data: Array? = null + var encoding: String = "" + var x: Int = 0 + var y: Int = 0 + var width: Int = 0 + var height: Int = 0 + var name: String = "" + var opacity: Float = 1f + var type: String = "" + var visible: Boolean = true + var draworder: String = "" } class MapTileset { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var firstgid: Int = 0 - var image: String = "" - var imageheight: Int = 0 - var imagewidth: Int = 0 - var margin: Int = 0 - var name: String = "" - var spacing: Int = 0 - var tilecount: Int = 0 - var tileheight: Int = 0 - var tilewidth: Int = 0 - var tileproperties: MutableMap> = HashMap() + var firstgid: Int = 0 + var image: String = "" + var imageheight: Int = 0 + var imagewidth: Int = 0 + var margin: Int = 0 + var name: String = "" + var spacing: Int = 0 + var tilecount: Int = 0 + var tileheight: Int = 0 + var tilewidth: Int = 0 + var tileproperties: MutableMap> = HashMap() } class TilesetIndex( - val texture: Texture?, - val tcLeft: Float, - val tcTop: Float, - val tcRight: Float, - val tcBottom: Float, - val scale: Float - ) { - constructor() : this(null, 0f, 0f, 0f, 0f, 0f) + val texture: Texture?, + val tcLeft: Float, + val tcTop: Float, + val tcRight: Float, + val tcBottom: Float, + val scale: Float +) { + constructor() : this(null, 0f, 0f, 0f, 0f, 0f) - fun render(x: Float, y: Float) { - texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) - } + fun render(x: Float, y: Float) { + texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) + } } class TiledMap(dir: String = "", url: String) { - val properties: Map = HashMap() - val data: MapData - val tileset: Array - val tiles: Array - var first = true - //var tilesetIndex: Array = Array(0, { TilesetIndex() }) + val properties: Map = HashMap() + val data: MapData + val tileset: Array + val tiles: Array + var first = true + //var tilesetIndex: Array = Array(0, { TilesetIndex() }) - init { - var tileDir = dir - if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { - tileDir = tileDir + "/" - } - - data = JSON.parse(getUrlAsString(tileDir + url)) - //println("map data is loaded") - val tilesets = data.tilesets - if (tilesets != null) { - tileset = Array(tilesets.size, { "" }) - var maxGid = 0 - for (index in 0..tilesets.size - 1) { - tileset[index] = tilesets[index].name - Textures.load(tilesets[index].name, tileDir + tilesets[index].image) - maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) - } - - tiles = Array(maxGid, { TilesetIndex() }) - } else { - tileset = Array(0, { "" }) - tiles = Array(0, { TilesetIndex() }) - } - - cacheTiles() + init { + var tileDir = dir + if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { + tileDir = tileDir + "/" } - fun cacheTiles() { - if (!Textures.ready()) { - window.setTimeout({ cacheTiles() }, 10) - } else { - val tilesets = data.tilesets - var tcLeft = 0f - var tcTop = 0f - var tcRight = 0f - var tcBottom = 0f + data = JSON.parse(getUrlAsString(tileDir + url)) + //println("map data is loaded") + val tilesets = data.tilesets + if (tilesets != null) { + tileset = Array(tilesets.size, { "" }) + var maxGid = 0 + for (index in 0..tilesets.size - 1) { + tileset[index] = tilesets[index].name + Textures.load(tilesets[index].name, tileDir + tilesets[index].image) + maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) + } - if (tilesets != null) { - - - for (tileset in tilesets) { - val tilesHor = tileset.imagewidth / tileset.tilewidth - val tilesVer = tileset.imageheight / tileset.tileheight - val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) - - for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { - val texture = Textures.get(tileset.name) - - val gid = index - tileset.firstgid - - val xi = gid % tilesHor - var yi = gid / tilesHor - yi = tilesVer - yi - 1 - val tw = 1f / tilesHor.toFloat() - val th = 1f / tilesVer.toFloat() - - val pixelW = 0.1f / tileset.tilewidth - val pixelH = 0.1f / tileset.tileheight - - tcLeft = xi * tw - tcRight = tcLeft + tw - - // switch up/down because of texture coord 0,0 in left bottom corner - tcBottom = yi * th - tcTop = tcBottom + th - - tcLeft += pixelW - tcRight -= pixelW - - tcBottom += pixelH - tcTop -= pixelH - - tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) - } - } - } - } + tiles = Array(maxGid, { TilesetIndex() }) + } else { + tileset = Array(0, { "" }) + tiles = Array(0, { TilesetIndex() }) } - fun drawTile(tile: Int, x: Float, y: Float) { - tiles[tile].render(x, y) + cacheTiles() + } + + fun cacheTiles() { + if (!Textures.ready()) { + window.setTimeout({ cacheTiles() }, 10) + } else { + val tilesets = data.tilesets + var tcLeft = 0f + var tcTop = 0f + var tcRight = 0f + var tcBottom = 0f + + if (tilesets != null) { + + + for (tileset in tilesets) { + val tilesHor = tileset.imagewidth / tileset.tilewidth + val tilesVer = tileset.imageheight / tileset.tileheight + val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) + + for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { + val texture = Textures.get(tileset.name) + + val gid = index - tileset.firstgid + + val xi = gid % tilesHor + var yi = gid / tilesHor + yi = tilesVer - yi - 1 + val tw = 1f / tilesHor.toFloat() + val th = 1f / tilesVer.toFloat() + + val pixelW = 0.1f / tileset.tilewidth + val pixelH = 0.1f / tileset.tileheight + + tcLeft = xi * tw + tcRight = tcLeft + tw + + // switch up/down because of texture coord 0,0 in left bottom corner + tcBottom = yi * th + tcTop = tcBottom + th + + tcLeft += pixelW + tcRight -= pixelW + + tcBottom += pixelH + tcTop -= pixelH + + tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) + } + } + } + } + } + + fun drawTile(tile: Int, x: Float, y: Float) { + tiles[tile].render(x, y) + } + + fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { + var x = 0f + var y = 0f + val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") + val layer = layers[layerIndex] + + val layerData = layer.data + if (layerData != null) { + for (index in layerData.indices) { + // todo: determine if in view + // todo: determine tilewidth + //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { + drawTile(layerData[index], xo + x * 128f, yo + y * 128f) + + when (data.renderorder) { + "right-down" -> { + x++ + if (x >= layer.width) { + x = 0f + y-- + } + } + else -> { + throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") + } + } + //} + } } - fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { - var x = 0f - var y = 0f - val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") - val layer = layers[layerIndex] + val tilesets = data.tilesets + if (tilesets != null) { + for (tileset in tilesets) { + if (Textures.has(tileset.name)) { + val tx = Textures.get(tileset.name) - val layerData = layer.data - if (layerData != null) { - for (index in layerData.indices) { - // todo: determine if in view - // todo: determine tilewidth - //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { - drawTile(layerData[index], xo + x * 128f, yo + y * 128f) - - when (data.renderorder) { - "right-down" -> { - x++ - if (x >= layer.width) { - x = 0f - y-- - } - } - else -> { - throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") - } - } - //} - } + tx.render() } - - val tilesets = data.tilesets - if (tilesets != null) { - for (tileset in tilesets) { - if (Textures.has(tileset.name)) { - val tx = Textures.get(tileset.name) - - tx.render() - } - } - } - - - first = false + } } + + + first = false + } } diff --git a/src/main/kotlin/games/perses/math/Matrix4.kt b/src/main/kotlin/games/perses/math/Matrix4.kt index 7da03cd..bd274bf 100644 --- a/src/main/kotlin/games/perses/math/Matrix4.kt +++ b/src/main/kotlin/games/perses/math/Matrix4.kt @@ -10,184 +10,184 @@ */ class Matrix4 { - internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - internal var temp = FloatArray(16) + internal var temp = FloatArray(16) - private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - fun get(): FloatArray { - return matrix + fun get(): FloatArray { + return matrix + } + + fun getFloat32Array() = Float32Array(get().toTypedArray()) + + fun set(values: FloatArray) { + if (values.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun getFloat32Array() = Float32Array(get().toTypedArray()) + matrix = values + } - fun set(values: FloatArray) { - if (values.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } + fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { + val r = (angle / 180f * Math.PI).toFloat() + val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() - matrix = values + matrix[0] = f / imageAspectRatio + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + + matrix[4] = 0.0f + matrix[5] = f + matrix[6] = 0.0f + matrix[7] = 0.0f + + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = -(far + near) / (far - near) + matrix[11] = -1.0f + + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = -(2.0f * far * near) / (far - near) + matrix[15] = 0.0f + } + + fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { + matrix[0] = 2f / (right - left) + matrix[1] = 0f + matrix[2] = 0f + matrix[3] = 0f + + matrix[4] = 0f + matrix[5] = 2f / (top - bottom) + matrix[6] = 0f + matrix[7] = 0f + + matrix[8] = 0f + matrix[9] = 0f + matrix[10] = -2f / (far - near) + matrix[11] = 0f + + matrix[12] = -(right + left) / (right - left) + matrix[13] = -(top + bottom) / (top - bottom) + matrix[14] = -(far + near) / (far - near) + matrix[15] = 1f + } + + fun setToIdentity() { + matrix[0] = 1.0f + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + matrix[4] = 0.0f + matrix[5] = 1.0f + matrix[6] = 0.0f + matrix[7] = 0.0f + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = 1.0f + matrix[11] = 0.0f + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = 0.0f + matrix[15] = 1.0f + } + + fun mul(other: Matrix4) { + mul(other.get()) + } + + protected fun mul(other: FloatArray) { + if (other.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { - val r = (angle / 180f * Math.PI).toFloat() - val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() + temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] + temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] + temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] + temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] + temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] + temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] + temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] + temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] + temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] + temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] + temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] + temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] + temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] + temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] + temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] + temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - matrix[0] = f / imageAspectRatio - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f + matrix[0] = temp[0] + matrix[1] = temp[1] + matrix[2] = temp[2] + matrix[3] = temp[3] + matrix[4] = temp[4] + matrix[5] = temp[5] + matrix[6] = temp[6] + matrix[7] = temp[7] + matrix[8] = temp[8] + matrix[9] = temp[9] + matrix[10] = temp[10] + matrix[11] = temp[11] + matrix[12] = temp[12] + matrix[13] = temp[13] + matrix[14] = temp[14] + matrix[15] = temp[15] + } - matrix[4] = 0.0f - matrix[5] = f - matrix[6] = 0.0f - matrix[7] = 0.0f + fun translate(x: Float, y: Float, z: Float) { + translateMatrix[12] = x + translateMatrix[13] = y + translateMatrix[14] = z - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = -(far + near) / (far - near) - matrix[11] = -1.0f + mul(translateMatrix) + } - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = -(2.0f * far * near) / (far - near) - matrix[15] = 0.0f - } + fun scale(x: Float, y: Float, z: Float) { + scaleMatrix[0] = x + scaleMatrix[5] = y + scaleMatrix[10] = z - fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { - matrix[0] = 2f / (right - left) - matrix[1] = 0f - matrix[2] = 0f - matrix[3] = 0f + mul(scaleMatrix) + } - matrix[4] = 0f - matrix[5] = 2f / (top - bottom) - matrix[6] = 0f - matrix[7] = 0f + fun rotateX(angle: Float) { + rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() + rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() + rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() + rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - matrix[8] = 0f - matrix[9] = 0f - matrix[10] = -2f / (far - near) - matrix[11] = 0f + mul(rotateXMatrix) + } - matrix[12] = - (right + left) / (right - left) - matrix[13] = - (top + bottom) / (top - bottom) - matrix[14] = - (far + near) / (far - near) - matrix[15] = 1f - } + fun rotateY(angle: Float) { + rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() + rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() + rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - fun setToIdentity() { - matrix[0] = 1.0f - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f - matrix[4] = 0.0f - matrix[5] = 1.0f - matrix[6] = 0.0f - matrix[7] = 0.0f - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = 1.0f - matrix[11] = 0.0f - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = 0.0f - matrix[15] = 1.0f - } + mul(rotateYMatrix) + } - fun mul(other: Matrix4) { - mul(other.get()) - } + fun rotateZ(angle: Float) { + rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() + rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() + rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - protected fun mul(other: FloatArray) { - if (other.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } - - temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] - temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] - temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] - temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] - temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] - temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] - temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] - temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] - temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] - temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] - temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] - temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] - temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] - temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] - temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] - temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - - matrix[0] = temp[0] - matrix[1] = temp[1] - matrix[2] = temp[2] - matrix[3] = temp[3] - matrix[4] = temp[4] - matrix[5] = temp[5] - matrix[6] = temp[6] - matrix[7] = temp[7] - matrix[8] = temp[8] - matrix[9] = temp[9] - matrix[10] = temp[10] - matrix[11] = temp[11] - matrix[12] = temp[12] - matrix[13] = temp[13] - matrix[14] = temp[14] - matrix[15] = temp[15] - } - - fun translate(x: Float, y: Float, z: Float) { - translateMatrix[12] = x - translateMatrix[13] = y - translateMatrix[14] = z - - mul(translateMatrix) - } - - fun scale(x: Float, y: Float, z: Float) { - scaleMatrix[0] = x - scaleMatrix[5] = y - scaleMatrix[10] = z - - mul(scaleMatrix) - } - - fun rotateX(angle: Float) { - rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() - rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() - rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() - rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateXMatrix) - } - - fun rotateY(angle: Float) { - rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() - rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() - rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateYMatrix) - } - - fun rotateZ(angle: Float) { - rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() - rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() - rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateZMatrix) - } + mul(rotateZMatrix) + } } diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml index 43edcc2..7ed1494 100644 --- a/.idea/modules/kudens_test.iml +++ b/.idea/modules/kudens_test.iml @@ -1,8 +1,9 @@ - + + $MODULE_DIR$/../../build/kotlinjs/kudens.js \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7ae9969..e7225a0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'perses.games' -version '1.1.6-SNAPSHOT' +version '1.1.7-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'idea' @@ -20,7 +20,7 @@ } buildscript { - ext.kotlin_version = '1.2.21' + ext.kotlin_version = '1.2.30' repositories { maven { url "http://nexus.astraeus.nl/nexus/content/groups/public" diff --git a/src/main/kotlin/games/perses/color/Color.kt b/src/main/kotlin/games/perses/color/Color.kt index 7f235b0..31b540f 100644 --- a/src/main/kotlin/games/perses/color/Color.kt +++ b/src/main/kotlin/games/perses/color/Color.kt @@ -10,107 +10,107 @@ object Color { - /** - * Converts an HSL color value to RGB. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes h, s, and l are contained in the set [0, 1] and - * returns r, g, and b in the set [0, 255]. + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. - * @param h The hue - * * - * @param s The saturation - * * - * @param l The lightness - * * - * @return int array, the RGB representation - */ - fun hslToRgb(h: Float, s: Float, l: Float): IntArray { - val r: Float - val g: Float - val b: Float + * @param h The hue + * * + * @param s The saturation + * * + * @param l The lightness + * * + * @return int array, the RGB representation + */ + fun hslToRgb(h: Float, s: Float, l: Float): IntArray { + val r: Float + val g: Float + val b: Float - if (s == 0f) { - b = l - g = b - r = g // achromatic - } else { - val q = if (l < 0.5f) l * (1 + s) else l + s - l * s - val p = 2 * l - q - r = hueToRgb(p, q, h + 1f / 3f) - g = hueToRgb(p, q, h) - b = hueToRgb(p, q, h - 1f / 3f) - } - val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) + if (s == 0f) { + b = l + g = b + r = g // achromatic + } else { + val q = if (l < 0.5f) l * (1 + s) else l + s - l * s + val p = 2 * l - q + r = hueToRgb(p, q, h + 1f / 3f) + g = hueToRgb(p, q, h) + b = hueToRgb(p, q, h - 1f / 3f) + } + val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) - return rgb + return rgb + } + + /** Helper method that converts hue to rgb */ + fun hueToRgb(p: Float, q: Float, t: Float): Float { + var lt = t + if (lt < 0f) { + lt += 1f + } + if (lt > 1f) { + lt -= 1f + } + if (lt < 1f / 6f) { + return p + (q - p) * 6f * lt + } + if (lt < 1f / 2f) { + return q + } + if (lt < 2f / 3f) { + return p + (q - p) * (2f / 3f - lt) * 6f + } + return p + } + + /** + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes pR, pG, and bpBare contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + + * @param pR The red color value + * * + * @param pG The green color value + * * + * @param pB The blue color value + * * + * @return float array, the HSL representation + */ + fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { + val r = pR / 255f + val g = pG / 255f + val b = pB / 255f + + val max = if (r > g && r > b) r else if (g > b) g else b + val min = if (r < g && r < b) r else if (g < b) g else b + + var h: Float + val s: Float + val l: Float + l = (max + min) / 2.0f + + if (max == min) { + s = 0.0f + h = s + } else { + val d = max - min + s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) + + if (r > g && r > b) + h = (g - b) / d + (if (g < b) 6.0f else 0.0f) + else if (g > b) + h = (b - r) / d + 2.0f + else + h = (r - g) / d + 4.0f + + h /= 6.0f } - /** Helper method that converts hue to rgb */ - fun hueToRgb(p: Float, q: Float, t: Float): Float { - var lt = t - if (lt < 0f) { - lt += 1f - } - if (lt > 1f) { - lt -= 1f - } - if (lt < 1f / 6f) { - return p + (q - p) * 6f * lt - } - if (lt < 1f / 2f) { - return q - } - if (lt < 2f / 3f) { - return p + (q - p) * (2f / 3f - lt) * 6f - } - return p - } - - /** - * Converts an RGB color value to HSL. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes pR, pG, and bpBare contained in the set [0, 255] and - * returns h, s, and l in the set [0, 1]. - - * @param pR The red color value - * * - * @param pG The green color value - * * - * @param pB The blue color value - * * - * @return float array, the HSL representation - */ - fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { - val r = pR / 255f - val g = pG / 255f - val b = pB / 255f - - val max = if (r > g && r > b) r else if (g > b) g else b - val min = if (r < g && r < b) r else if (g < b) g else b - - var h: Float - val s: Float - val l: Float - l = (max + min) / 2.0f - - if (max == min) { - s = 0.0f - h = s - } else { - val d = max - min - s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) - - if (r > g && r > b) - h = (g - b) / d + (if (g < b) 6.0f else 0.0f) - else if (g > b) - h = (b - r) / d + 2.0f - else - h = (r - g) / d + 4.0f - - h /= 6.0f - } - - val hsl = floatArrayOf(h, s, l) - return hsl - } + val hsl = floatArrayOf(h, s, l) + return hsl + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/game/Game.kt b/src/main/kotlin/games/perses/game/Game.kt index 0961316..1becee5 100644 --- a/src/main/kotlin/games/perses/game/Game.kt +++ b/src/main/kotlin/games/perses/game/Game.kt @@ -14,210 +14,210 @@ */ enum class DrawMode { - LINEAR, - NEAREST + LINEAR, + NEAREST } class HTMLElements { - var container: HTMLElement - var webgl: WebGLRenderingContext - var canvas2d: CanvasRenderingContext2D + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D - init { - container = document.createElement("div") as HTMLElement + init { + container = document.createElement("div") as HTMLElement - val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement - val canvas = document.createElement("canvas") as HTMLCanvasElement + val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + val canvas = document.createElement("canvas") as HTMLCanvasElement - container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") - webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" ) - canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" ) + container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;") - document.body!!.appendChild(container) - container.appendChild(webGlCanvas) - container.appendChild(canvas) + document.body!!.appendChild(container) + container.appendChild(webGlCanvas) + container.appendChild(canvas) - val canvas2dcanvas = canvas.getContext("2d") + val canvas2dcanvas = canvas.getContext("2d") - var webglcanvas = webGlCanvas.getContext("webgl") - if (webglcanvas == null) { - console.log("webgl context not found, trying experimental-webgl.") - webglcanvas = webGlCanvas.getContext("experimental-webgl") - } - - if (webglcanvas != null) { - webgl = webglcanvas as WebGLRenderingContext - } else { - console.log("webgl?", webglcanvas) - window.alert("Your browser doesn't seem to support webgl!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } - - if (canvas2dcanvas != null) { - canvas2d = canvas2dcanvas as CanvasRenderingContext2D - } else { - console.log("canvas2d?", canvas2dcanvas) - window.alert("Your browser doesn't seem to support 2d canvas!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } + var webglcanvas = webGlCanvas.getContext("webgl") + if (webglcanvas == null) { + console.log("webgl context not found, trying experimental-webgl.") + webglcanvas = webGlCanvas.getContext("experimental-webgl") } + + if (webglcanvas != null) { + webgl = webglcanvas as WebGLRenderingContext + } else { + console.log("webgl?", webglcanvas) + window.alert("Your browser doesn't seem to support webgl!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + + if (canvas2dcanvas != null) { + canvas2d = canvas2dcanvas as CanvasRenderingContext2D + } else { + console.log("canvas2d?", canvas2dcanvas) + window.alert("Your browser doesn't seem to support 2d canvas!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + } } object Game { - var started = false - val view: View = View() - val html: HTMLElements by lazy { HTMLElements() } - var currentScreen: Screen = DefaultScreen() - var start = Date().getTime() - var currentTime = start - var currentDelta = 0f - var pause: Boolean = false - var clearScreenEveryFrame = true + var started = false + val view: View = View() + val html: HTMLElements by lazy { HTMLElements() } + var currentScreen: Screen = DefaultScreen() + var start = Date().getTime() + var currentTime = start + var currentDelta = 0f + var pause: Boolean = false + var clearScreenEveryFrame = true - var clearRed = 0f - var clearGreen = 0f - var clearBlue = 0f - var clearAlpha = 1f + var clearRed = 0f + var clearGreen = 0f + var clearBlue = 0f + var clearAlpha = 1f - var fps = 0 - var fpsCount = 0 - var fpsCountTime = 0f + var fps = 0 + var fpsCount = 0 + var fpsCountTime = 0f - var borderLeft = 0 - var borderTop = 0 + var borderLeft = 0 + var borderTop = 0 - var focus = true + var focus = true - init { - window.onfocus = { - //println("GOT FOCUS!") + init { + window.onfocus = { + //println("GOT FOCUS!") - focus = true - "" - } - window.onblur = { - //println("LOST FOCUS!") + focus = true + "" + } + window.onblur = { + //println("LOST FOCUS!") - focus = false - "" - } - + focus = false + "" } - fun gl() = html.webgl + } - fun resize() { - val canvas = gl().canvas + fun gl() = html.webgl - // Check if the canvas is not the same size. - val windowWidth = window.innerWidth.toInt() - val windowHeight = window.innerHeight.toInt() + fun resize() { + val canvas = gl().canvas - if (view.lastWindowWidth != windowWidth || - view.lastWindowHeight != windowHeight) { - view.lastWindowWidth = windowWidth - view.lastWindowHeight = windowHeight - view.windowWidth = windowWidth - view.windowHeight = windowHeight + // Check if the canvas is not the same size. + val windowWidth = window.innerWidth.toInt() + val windowHeight = window.innerHeight.toInt() - view.updateView() + if (view.lastWindowWidth != windowWidth || + view.lastWindowHeight != windowHeight) { + view.lastWindowWidth = windowWidth + view.lastWindowHeight = windowHeight + view.windowWidth = windowWidth + view.windowHeight = windowHeight - val textCanvas = html.canvas2d.canvas + view.updateView() - // Make the canvas the same size - canvas.width = view.width.toInt() - canvas.height = view.height.toInt() + val textCanvas = html.canvas2d.canvas - textCanvas.width = view.width.toInt() - textCanvas.height = view.height.toInt() + // Make the canvas the same size + canvas.width = view.width.toInt() + canvas.height = view.height.toInt() - gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) + textCanvas.width = view.width.toInt() + textCanvas.height = view.height.toInt() - borderLeft = (windowWidth - view.windowWidth) / 2 - borderTop = (windowHeight - view.windowHeight) / 2 + gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) - canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) - textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) + borderLeft = (windowWidth - view.windowWidth) / 2 + borderTop = (windowHeight - view.windowHeight) / 2 + + canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + } + } + + fun start(startScreen: Screen) { + if (started) { + throw IllegalStateException("You can only start a game once!") + } + + setScreen(startScreen) + + // start game loop + started = true + gameLoop() + } + + fun setScreen(screen: Screen) { + currentScreen.unloadResources() + + currentScreen = screen + + screen.loadResources() + } + + fun setClearColor(r: Float, g: Float, b: Float, a: Float) { + clearRed = r + clearGreen = g + clearBlue = b + clearAlpha = a + } + + fun gameLoop() { + try { + if (!Textures.ready()) { + gl().clearColor(1f, 1f, 1f, 1f) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } else { + resize() + + if (!pause) { + html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); + + if (clearScreenEveryFrame) { + gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } + + gl().enable(WebGLRenderingContext.BLEND) + gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); + + val time = Date().getTime() + currentDelta = ((time - currentTime) / 1000f).toFloat() + currentTime = time + + val timeInSeconds = (currentTime - start) / 1000f + + fpsCountTime += currentDelta + fpsCount++ + while (fpsCountTime > 1f) { + fps = fpsCount + fpsCountTime -= 1f + fpsCount = 0 + } + + if (focus) { + currentScreen.update(timeInSeconds.toFloat(), currentDelta) + } + + currentScreen.render() } + } + } catch (e: Exception) { + println("Some error...") + console.log(e) } - fun start(startScreen: Screen) { - if (started) { - throw IllegalStateException("You can only start a game once!") - } - - setScreen(startScreen) - - // start game loop - started = true - gameLoop() + window.requestAnimationFrame { + gameLoop() } - - fun setScreen(screen: Screen) { - currentScreen.unloadResources() - - currentScreen = screen - - screen.loadResources() - } - - fun setClearColor(r: Float, g: Float, b: Float, a: Float) { - clearRed = r - clearGreen = g - clearBlue = b - clearAlpha = a - } - - fun gameLoop() { - try { - if (!Textures.ready()) { - gl().clearColor(1f, 1f, 1f, 1f) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } else { - resize() - - if (!pause) { - html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); - - if (clearScreenEveryFrame) { - gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } - - gl().enable(WebGLRenderingContext.BLEND) - gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); - - val time = Date().getTime() - currentDelta = ((time - currentTime) / 1000f).toFloat() - currentTime = time - - val timeInSeconds = (currentTime - start) / 1000f - - fpsCountTime += currentDelta - fpsCount++ - while (fpsCountTime > 1f) { - fps = fpsCount - fpsCountTime -= 1f - fpsCount = 0 - } - - if (focus) { - currentScreen.update(timeInSeconds.toFloat(), currentDelta) - } - - currentScreen.render() - } - } - } catch(e: Exception) { - println("Some error...") - console.log(e) - } - - window.requestAnimationFrame { - gameLoop() - } - } + } } diff --git a/src/main/kotlin/games/perses/game/Screen.kt b/src/main/kotlin/games/perses/game/Screen.kt index 10b6eae..7b381e7 100644 --- a/src/main/kotlin/games/perses/game/Screen.kt +++ b/src/main/kotlin/games/perses/game/Screen.kt @@ -8,31 +8,31 @@ abstract class Screen { - open fun loadResources() {} + open fun loadResources() {} - @Deprecated( + @Deprecated( message = "replace with unloadResources", replaceWith = ReplaceWith("unloadResources()") - ) - open fun closeResources() { - unloadResources() - } + ) + open fun closeResources() { + unloadResources() + } - open fun unloadResources() {} + open fun unloadResources() {} - abstract fun update(time: Float, delta: Float) + abstract fun update(time: Float, delta: Float) - abstract fun render() + abstract fun render() } -class DefaultScreen: Screen() { - override fun update(time: Float, delta: Float) { - } +class DefaultScreen : Screen() { + override fun update(time: Float, delta: Float) { + } - override fun render() { - // show loading message? - Game.gl().clearColor(1f, 1f, 0f, 1f) - Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } + override fun render() { + // show loading message? + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } } diff --git a/src/main/kotlin/games/perses/game/View.kt b/src/main/kotlin/games/perses/game/View.kt index 540a44d..16c9913 100644 --- a/src/main/kotlin/games/perses/game/View.kt +++ b/src/main/kotlin/games/perses/game/View.kt @@ -4,39 +4,39 @@ import kotlin.browser.document enum class ViewType { - PROJECTION, - WIDTH, - HEIGHT, - ABSOLUTE + PROJECTION, + WIDTH, + HEIGHT, + ABSOLUTE } class View( - var lastWindowWidth: Int = 2000, - var lastWindowHeight: Int = 1000, - var windowWidth: Int = 2000, - var windowHeight: Int = 1000, - var width: Float = 1024f, - var height: Float = 1024f, - var angle: Float = 60f, - var near: Float = -0.1f, - var far: Float = -100f, - var minAspectRatio: Float = 1f, - var maxAspectRatio: Float = 1f, - var leftOffset: Int = 0, - var bottomOffset: Int = 0, - var viewType: ViewType = ViewType.WIDTH, - var drawMode: DrawMode = DrawMode.LINEAR) { - var vMatrix = Matrix4() - var aspectRatio = 1f + var lastWindowWidth: Int = 2000, + var lastWindowHeight: Int = 1000, + var windowWidth: Int = 2000, + var windowHeight: Int = 1000, + var width: Float = 1024f, + var height: Float = 1024f, + var angle: Float = 60f, + var near: Float = -0.1f, + var far: Float = -100f, + var minAspectRatio: Float = 1f, + var maxAspectRatio: Float = 1f, + var leftOffset: Int = 0, + var bottomOffset: Int = 0, + var viewType: ViewType = ViewType.WIDTH, + var drawMode: DrawMode = DrawMode.LINEAR) { + var vMatrix = Matrix4() + var aspectRatio = 1f - init { - updateView() - } + init { + updateView() + } - fun requestFullscreen() { - val element = document.body - //language=javascript - js(""" + fun requestFullscreen() { + val element = document.body + //language=javascript + js(""" if(element.requestFullscreen) { element.requestFullscreen(); } else if(element.mozRequestFullScreen) { @@ -47,10 +47,10 @@ element.msRequestFullscreen(); } """) - } + } - fun exitFullscreen() { - js(""" + fun exitFullscreen() { + js(""" if(document.exitFullscreen) { document.exitFullscreen(); } else if(document.mozCancelFullScreen) { @@ -59,178 +59,178 @@ document.webkitExitFullscreen(); } """) + } + + fun switchFullscreen() { + if (isFullscreen()) { + exitFullscreen() + } else { + requestFullscreen() + } + } + + fun isFullscreen(): Boolean { + val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + + return fse != undefined + } + + fun updateView() { + aspectRatio = windowWidth / windowHeight.toFloat() + + if (aspectRatio < minAspectRatio) { + aspectRatio = minAspectRatio + + windowHeight = (windowWidth / aspectRatio).toInt() } - fun switchFullscreen() { - if (isFullscreen()) { - exitFullscreen() - } else { - requestFullscreen() - } + if (aspectRatio > maxAspectRatio) { + aspectRatio = maxAspectRatio + + windowWidth = (windowHeight * aspectRatio).toInt() } - fun isFullscreen(): Boolean { - val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + when (viewType) { + ViewType.ABSOLUTE -> { + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.WIDTH -> { + height = width / aspectRatio - return fse != undefined + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.HEIGHT -> { + width = height * aspectRatio + + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.PROJECTION -> { + vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun updateView() { - aspectRatio = windowWidth / windowHeight.toFloat() + //println("width: $width, height: $height") + } - if (aspectRatio < minAspectRatio) { - aspectRatio = minAspectRatio + fun screenToGameCoordX(screenX: Float): Float { + var result = screenX - windowHeight = (windowWidth / aspectRatio).toInt() - } - - if (aspectRatio > maxAspectRatio) { - aspectRatio = maxAspectRatio - - windowWidth = (windowHeight * aspectRatio).toInt() - } - - when (viewType) { - ViewType.ABSOLUTE -> { - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.WIDTH -> { - height = width / aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.HEIGHT -> { - width = height * aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.PROJECTION -> { - vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } - - //println("width: $width, height: $height") + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = ((screenX - Game.borderLeft) * width / windowWidth) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordX(screenX: Float): Float { - var result = screenX + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( (screenX - Game.borderLeft) * width / windowWidth ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun screenToGameCoordY(screenY: Float): Float { + var result = screenY - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - ((screenY - Game.borderTop) * height / windowHeight) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordY(screenY: Float): Float { - var result = screenY + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( (screenY - Game.borderTop) * height / windowHeight ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordX(gameX: Float): Float { + var result = gameX + val normalizedX = gameX + (width / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = (gameX / width * windowWidth) + Game.borderLeft + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordX(gameX: Float): Float { - var result = gameX - val normalizedX = gameX + (width / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( gameX / width * windowWidth ) + Game.borderLeft - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordY(gameY: Float): Float { + var result = gameY + val normalizedY = gameY + (height / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - (gameY / height * windowHeight) + Game.borderTop + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordY(gameY: Float): Float { - var result = gameY - val normalizedY = gameY + (height / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( gameY / height * windowHeight ) + Game.borderTop - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun setToWidth(width: Float) { + this.width = width + this.viewType = ViewType.WIDTH - return result - } + updateView() + } - fun setToWidth(width: Float) { - this.width = width - this.viewType = ViewType.WIDTH + fun setToHeight(height: Float) { + this.height = height + this.viewType = ViewType.HEIGHT - updateView() - } + updateView() + } - fun setToHeight(height: Float) { - this.height = height - this.viewType = ViewType.HEIGHT + fun setProjection(angle: Float) { + this.angle = angle + this.viewType = ViewType.PROJECTION - updateView() - } + updateView() + } - fun setProjection(angle: Float) { - this.angle = angle - this.viewType = ViewType.PROJECTION + fun setNear(near: Float) { + this.near = near - updateView() - } + updateView() + } - fun setNear(near: Float) { - this.near = near + fun setFar(far: Float) { + this.far = far - updateView() - } - - fun setFar(far: Float) { - this.far = far - - updateView() - } + updateView() + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/input/Input.kt b/src/main/kotlin/games/perses/input/Input.kt index 71a3adc..58c4f23 100644 --- a/src/main/kotlin/games/perses/input/Input.kt +++ b/src/main/kotlin/games/perses/input/Input.kt @@ -15,235 +15,235 @@ */ enum class KeyCode(val keyCode: Int) { - BACKSPACE(8), - TAB(9), - ENTER(13), - SHIFT(16), - CTRL(17), - ALT(18), - PAUSE_BREAK(19), - CAPS_LOCK(20), - ESCAPE(27), - SPACE(32), - PAGE_UP(33), - PAGE_DOWN(34), - END(35), - HOME(36), - LEFT_ARROW(37), - UP_ARROW(38), - RIGHT_ARROW(39), - DOWN_ARROW(40), - INSERT(45), - DELETE(46), - NR_0(48), - NR_1(49), - NR_2(50), - NR_3(51), - NR_4(52), - NR_5(53), - NR_6(54), - NR_7(55), - NR_8(56), - NR_9(57), - A(65), - B(66), - C(67), - D(68), - E(69), - F(70), - G(71), - H(72), - I(73), - J(74), - K(75), - L(76), - M(77), - N(78), - O(79), - P(80), - Q(81), - R(82), - S(83), - T(84), - U(85), - V(86), - W(87), - X(88), - Y(89), - Z(90), - LEFT_WINDOW_KEY(91), - RIGHT_WINDOW_KEY(92), - SELECT_KEY(93), - NUMPAD_0(96), - NUMPAD_1(97), - NUMPAD_2(98), - NUMPAD_3(99), - NUMPAD_4(100), - NUMPAD_5(101), - NUMPAD_6(102), - NUMPAD_7(103), - NUMPAD_8(104), - NUMPAD_9(105), - MULTIPLY(106), - ADD(107), - SUBTRACT(109), - DECIMAL_POINT(110), - DIVIDE(111), - F1(112), - F2(113), - F3(114), - F4(115), - F5(116), - F6(117), - F7(118), - F8(119), - F9(120), - F10(121), - F11(122), - F12(123), - NUM_LOCK(144), - SCROLL_LOCK(145), - SEMI_COLON(186), - EQUAL_SIGN(187), - COMMA(188), - DASH(189), - PERIOD(190), - FORWARD_SLASH(191), - GRAVE_ACCENT(192), - OPEN_BRACKET(219), - BACK_SLASH(220), - CLOSE_BRAKET(221), - SINGLE_QUOTE(222), + BACKSPACE(8), + TAB(9), + ENTER(13), + SHIFT(16), + CTRL(17), + ALT(18), + PAUSE_BREAK(19), + CAPS_LOCK(20), + ESCAPE(27), + SPACE(32), + PAGE_UP(33), + PAGE_DOWN(34), + END(35), + HOME(36), + LEFT_ARROW(37), + UP_ARROW(38), + RIGHT_ARROW(39), + DOWN_ARROW(40), + INSERT(45), + DELETE(46), + NR_0(48), + NR_1(49), + NR_2(50), + NR_3(51), + NR_4(52), + NR_5(53), + NR_6(54), + NR_7(55), + NR_8(56), + NR_9(57), + A(65), + B(66), + C(67), + D(68), + E(69), + F(70), + G(71), + H(72), + I(73), + J(74), + K(75), + L(76), + M(77), + N(78), + O(79), + P(80), + Q(81), + R(82), + S(83), + T(84), + U(85), + V(86), + W(87), + X(88), + Y(89), + Z(90), + LEFT_WINDOW_KEY(91), + RIGHT_WINDOW_KEY(92), + SELECT_KEY(93), + NUMPAD_0(96), + NUMPAD_1(97), + NUMPAD_2(98), + NUMPAD_3(99), + NUMPAD_4(100), + NUMPAD_5(101), + NUMPAD_6(102), + NUMPAD_7(103), + NUMPAD_8(104), + NUMPAD_9(105), + MULTIPLY(106), + ADD(107), + SUBTRACT(109), + DECIMAL_POINT(110), + DIVIDE(111), + F1(112), + F2(113), + F3(114), + F4(115), + F5(116), + F6(117), + F7(118), + F8(119), + F9(120), + F10(121), + F11(122), + F12(123), + NUM_LOCK(144), + SCROLL_LOCK(145), + SEMI_COLON(186), + EQUAL_SIGN(187), + COMMA(188), + DASH(189), + PERIOD(190), + FORWARD_SLASH(191), + GRAVE_ACCENT(192), + OPEN_BRACKET(219), + BACK_SLASH(220), + CLOSE_BRAKET(221), + SINGLE_QUOTE(222), - ESC(27), - LEFT(37), - UP(38), - DOWN(40), - RIGHT(39), - MINUS(109), - PLUS(107), + ESC(27), + LEFT(37), + UP(38), + DOWN(40), + RIGHT(39), + MINUS(109), + PLUS(107), } interface InputProcessor { - fun keyPressed(charCode: Int) + fun keyPressed(charCode: Int) - fun keyDown(keyCode: Int) + fun keyDown(keyCode: Int) - fun keyUp(keyCode: Int) + fun keyUp(keyCode: Int) - fun pointerClick(pointer: Int, x: Float, y: Float) + fun pointerClick(pointer: Int, x: Float, y: Float) - fun mouseMove(x: Float, y: Float) + fun mouseMove(x: Float, y: Float) } open class EmptyInputProcessor : InputProcessor { - override fun pointerClick(pointer: Int, x: Float, y: Float) { } + override fun pointerClick(pointer: Int, x: Float, y: Float) {} - override fun keyDown(keyCode: Int) { } + override fun keyDown(keyCode: Int) {} - override fun keyPressed(charCode: Int) { } + override fun keyPressed(charCode: Int) {} - override fun keyUp(keyCode: Int) { } + override fun keyUp(keyCode: Int) {} - override fun mouseMove(x: Float, y: Float) { } + override fun mouseMove(x: Float, y: Float) {} } object Input { - private val keys: MutableMap = HashMap() - private var inputProcesser: InputProcessor = EmptyInputProcessor() + private val keys: MutableMap = HashMap() + private var inputProcesser: InputProcessor = EmptyInputProcessor() - init { - val body = document.body - if (body != null) { - body.onkeydown = { - keyDown(it) - } + init { + val body = document.body + if (body != null) { + body.onkeydown = { + keyDown(it) + } - body.onkeyup = { - keyUp(it) - } + body.onkeyup = { + keyUp(it) + } - body.onkeypress = { - keyPress(it) - } + body.onkeypress = { + keyPress(it) + } - body.onclick = { - mouseClick(it) - } + body.onclick = { + mouseClick(it) + } - body.onmousedown = { - mouseMove(it) - } + body.onmousedown = { + mouseMove(it) + } - body.onmouseup = { - mouseMove(it) - } + body.onmouseup = { + mouseMove(it) + } - body.onmousemove = { - mouseMove(it) - } - } else { - console.log("Can't register key events, document.body is null!?") - } + body.onmousemove = { + mouseMove(it) + } + } else { + console.log("Can't register key events, document.body is null!?") } + } - fun setInputProcessor(processor: InputProcessor) { - this.inputProcesser = processor + fun setInputProcessor(processor: InputProcessor) { + this.inputProcesser = processor + } + + private fun keyDown(key: Event) { + if (key is KeyboardEvent) { + keys.put(key.keyCode, Date().getTime()) + + inputProcesser.keyDown(key.keyCode) } + } - private fun keyDown(key: Event) { - if (key is KeyboardEvent) { - keys.put(key.keyCode, Date().getTime()) + private fun keyUp(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyUp(key.keyCode) - inputProcesser.keyDown(key.keyCode) - } + keys.remove(key.keyCode) } + } - private fun keyUp(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyUp(key.keyCode) - - keys.remove(key.keyCode) - } + private fun keyPress(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyPressed(key.charCode) } + } - private fun keyPress(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyPressed(key.charCode) - } + private fun mouseClick(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + + inputProcesser.pointerClick(event.button.toInt(), vx, vy) } + } - private fun mouseClick(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + private fun mouseMove(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) - inputProcesser.pointerClick(event.button.toInt(), vx, vy) - } + inputProcesser.mouseMove(vx, vy) } + } - private fun mouseMove(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + fun isDown(keyCode: Int) = keys.containsKey(keyCode) - inputProcesser.mouseMove(vx, vy) - } - } + fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - fun isDown(keyCode: Int) = keys.containsKey(keyCode) + fun wasPressed(keyCode: Int, delta: Double): Boolean { + val time = keys[keyCode] - fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - - fun wasPressed(keyCode: Int, delta: Double): Boolean { - val time = keys[keyCode] - - return (time != null && time > (Date().getTime() - delta)) - } + return (time != null && time > (Date().getTime() - delta)) + } } diff --git a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt index f1c7808..f3d4126 100644 --- a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt +++ b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt @@ -11,201 +11,201 @@ */ class MapData { - var version: Int = 1 - var properties: MutableMap = HashMap() - var layers: Array? = null - var tilesets: Array? = null + var version: Int = 1 + var properties: MutableMap = HashMap() + var layers: Array? = null + var tilesets: Array? = null - var height: Int = 0 - var width: Int = 0 + var height: Int = 0 + var width: Int = 0 - var nextobjectid: Int = 0 - var orientation: String = "orthogonal" - var renderorder: String = "right-down" - var tileheight: Int = 0 - var tilewidth: Int = 0 + var nextobjectid: Int = 0 + var orientation: String = "orthogonal" + var renderorder: String = "right-down" + var tileheight: Int = 0 + var tilewidth: Int = 0 } class MapLayer { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var data: Array? = null - var encoding: String = "" - var x: Int = 0 - var y: Int = 0 - var width: Int = 0 - var height: Int = 0 - var name: String = "" - var opacity: Float = 1f - var type: String = "" - var visible: Boolean = true - var draworder: String = "" + var data: Array? = null + var encoding: String = "" + var x: Int = 0 + var y: Int = 0 + var width: Int = 0 + var height: Int = 0 + var name: String = "" + var opacity: Float = 1f + var type: String = "" + var visible: Boolean = true + var draworder: String = "" } class MapTileset { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var firstgid: Int = 0 - var image: String = "" - var imageheight: Int = 0 - var imagewidth: Int = 0 - var margin: Int = 0 - var name: String = "" - var spacing: Int = 0 - var tilecount: Int = 0 - var tileheight: Int = 0 - var tilewidth: Int = 0 - var tileproperties: MutableMap> = HashMap() + var firstgid: Int = 0 + var image: String = "" + var imageheight: Int = 0 + var imagewidth: Int = 0 + var margin: Int = 0 + var name: String = "" + var spacing: Int = 0 + var tilecount: Int = 0 + var tileheight: Int = 0 + var tilewidth: Int = 0 + var tileproperties: MutableMap> = HashMap() } class TilesetIndex( - val texture: Texture?, - val tcLeft: Float, - val tcTop: Float, - val tcRight: Float, - val tcBottom: Float, - val scale: Float - ) { - constructor() : this(null, 0f, 0f, 0f, 0f, 0f) + val texture: Texture?, + val tcLeft: Float, + val tcTop: Float, + val tcRight: Float, + val tcBottom: Float, + val scale: Float +) { + constructor() : this(null, 0f, 0f, 0f, 0f, 0f) - fun render(x: Float, y: Float) { - texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) - } + fun render(x: Float, y: Float) { + texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) + } } class TiledMap(dir: String = "", url: String) { - val properties: Map = HashMap() - val data: MapData - val tileset: Array - val tiles: Array - var first = true - //var tilesetIndex: Array = Array(0, { TilesetIndex() }) + val properties: Map = HashMap() + val data: MapData + val tileset: Array + val tiles: Array + var first = true + //var tilesetIndex: Array = Array(0, { TilesetIndex() }) - init { - var tileDir = dir - if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { - tileDir = tileDir + "/" - } - - data = JSON.parse(getUrlAsString(tileDir + url)) - //println("map data is loaded") - val tilesets = data.tilesets - if (tilesets != null) { - tileset = Array(tilesets.size, { "" }) - var maxGid = 0 - for (index in 0..tilesets.size - 1) { - tileset[index] = tilesets[index].name - Textures.load(tilesets[index].name, tileDir + tilesets[index].image) - maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) - } - - tiles = Array(maxGid, { TilesetIndex() }) - } else { - tileset = Array(0, { "" }) - tiles = Array(0, { TilesetIndex() }) - } - - cacheTiles() + init { + var tileDir = dir + if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { + tileDir = tileDir + "/" } - fun cacheTiles() { - if (!Textures.ready()) { - window.setTimeout({ cacheTiles() }, 10) - } else { - val tilesets = data.tilesets - var tcLeft = 0f - var tcTop = 0f - var tcRight = 0f - var tcBottom = 0f + data = JSON.parse(getUrlAsString(tileDir + url)) + //println("map data is loaded") + val tilesets = data.tilesets + if (tilesets != null) { + tileset = Array(tilesets.size, { "" }) + var maxGid = 0 + for (index in 0..tilesets.size - 1) { + tileset[index] = tilesets[index].name + Textures.load(tilesets[index].name, tileDir + tilesets[index].image) + maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) + } - if (tilesets != null) { - - - for (tileset in tilesets) { - val tilesHor = tileset.imagewidth / tileset.tilewidth - val tilesVer = tileset.imageheight / tileset.tileheight - val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) - - for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { - val texture = Textures.get(tileset.name) - - val gid = index - tileset.firstgid - - val xi = gid % tilesHor - var yi = gid / tilesHor - yi = tilesVer - yi - 1 - val tw = 1f / tilesHor.toFloat() - val th = 1f / tilesVer.toFloat() - - val pixelW = 0.1f / tileset.tilewidth - val pixelH = 0.1f / tileset.tileheight - - tcLeft = xi * tw - tcRight = tcLeft + tw - - // switch up/down because of texture coord 0,0 in left bottom corner - tcBottom = yi * th - tcTop = tcBottom + th - - tcLeft += pixelW - tcRight -= pixelW - - tcBottom += pixelH - tcTop -= pixelH - - tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) - } - } - } - } + tiles = Array(maxGid, { TilesetIndex() }) + } else { + tileset = Array(0, { "" }) + tiles = Array(0, { TilesetIndex() }) } - fun drawTile(tile: Int, x: Float, y: Float) { - tiles[tile].render(x, y) + cacheTiles() + } + + fun cacheTiles() { + if (!Textures.ready()) { + window.setTimeout({ cacheTiles() }, 10) + } else { + val tilesets = data.tilesets + var tcLeft = 0f + var tcTop = 0f + var tcRight = 0f + var tcBottom = 0f + + if (tilesets != null) { + + + for (tileset in tilesets) { + val tilesHor = tileset.imagewidth / tileset.tilewidth + val tilesVer = tileset.imageheight / tileset.tileheight + val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) + + for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { + val texture = Textures.get(tileset.name) + + val gid = index - tileset.firstgid + + val xi = gid % tilesHor + var yi = gid / tilesHor + yi = tilesVer - yi - 1 + val tw = 1f / tilesHor.toFloat() + val th = 1f / tilesVer.toFloat() + + val pixelW = 0.1f / tileset.tilewidth + val pixelH = 0.1f / tileset.tileheight + + tcLeft = xi * tw + tcRight = tcLeft + tw + + // switch up/down because of texture coord 0,0 in left bottom corner + tcBottom = yi * th + tcTop = tcBottom + th + + tcLeft += pixelW + tcRight -= pixelW + + tcBottom += pixelH + tcTop -= pixelH + + tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) + } + } + } + } + } + + fun drawTile(tile: Int, x: Float, y: Float) { + tiles[tile].render(x, y) + } + + fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { + var x = 0f + var y = 0f + val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") + val layer = layers[layerIndex] + + val layerData = layer.data + if (layerData != null) { + for (index in layerData.indices) { + // todo: determine if in view + // todo: determine tilewidth + //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { + drawTile(layerData[index], xo + x * 128f, yo + y * 128f) + + when (data.renderorder) { + "right-down" -> { + x++ + if (x >= layer.width) { + x = 0f + y-- + } + } + else -> { + throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") + } + } + //} + } } - fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { - var x = 0f - var y = 0f - val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") - val layer = layers[layerIndex] + val tilesets = data.tilesets + if (tilesets != null) { + for (tileset in tilesets) { + if (Textures.has(tileset.name)) { + val tx = Textures.get(tileset.name) - val layerData = layer.data - if (layerData != null) { - for (index in layerData.indices) { - // todo: determine if in view - // todo: determine tilewidth - //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { - drawTile(layerData[index], xo + x * 128f, yo + y * 128f) - - when (data.renderorder) { - "right-down" -> { - x++ - if (x >= layer.width) { - x = 0f - y-- - } - } - else -> { - throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") - } - } - //} - } + tx.render() } - - val tilesets = data.tilesets - if (tilesets != null) { - for (tileset in tilesets) { - if (Textures.has(tileset.name)) { - val tx = Textures.get(tileset.name) - - tx.render() - } - } - } - - - first = false + } } + + + first = false + } } diff --git a/src/main/kotlin/games/perses/math/Matrix4.kt b/src/main/kotlin/games/perses/math/Matrix4.kt index 7da03cd..bd274bf 100644 --- a/src/main/kotlin/games/perses/math/Matrix4.kt +++ b/src/main/kotlin/games/perses/math/Matrix4.kt @@ -10,184 +10,184 @@ */ class Matrix4 { - internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - internal var temp = FloatArray(16) + internal var temp = FloatArray(16) - private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - fun get(): FloatArray { - return matrix + fun get(): FloatArray { + return matrix + } + + fun getFloat32Array() = Float32Array(get().toTypedArray()) + + fun set(values: FloatArray) { + if (values.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun getFloat32Array() = Float32Array(get().toTypedArray()) + matrix = values + } - fun set(values: FloatArray) { - if (values.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } + fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { + val r = (angle / 180f * Math.PI).toFloat() + val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() - matrix = values + matrix[0] = f / imageAspectRatio + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + + matrix[4] = 0.0f + matrix[5] = f + matrix[6] = 0.0f + matrix[7] = 0.0f + + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = -(far + near) / (far - near) + matrix[11] = -1.0f + + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = -(2.0f * far * near) / (far - near) + matrix[15] = 0.0f + } + + fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { + matrix[0] = 2f / (right - left) + matrix[1] = 0f + matrix[2] = 0f + matrix[3] = 0f + + matrix[4] = 0f + matrix[5] = 2f / (top - bottom) + matrix[6] = 0f + matrix[7] = 0f + + matrix[8] = 0f + matrix[9] = 0f + matrix[10] = -2f / (far - near) + matrix[11] = 0f + + matrix[12] = -(right + left) / (right - left) + matrix[13] = -(top + bottom) / (top - bottom) + matrix[14] = -(far + near) / (far - near) + matrix[15] = 1f + } + + fun setToIdentity() { + matrix[0] = 1.0f + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + matrix[4] = 0.0f + matrix[5] = 1.0f + matrix[6] = 0.0f + matrix[7] = 0.0f + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = 1.0f + matrix[11] = 0.0f + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = 0.0f + matrix[15] = 1.0f + } + + fun mul(other: Matrix4) { + mul(other.get()) + } + + protected fun mul(other: FloatArray) { + if (other.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { - val r = (angle / 180f * Math.PI).toFloat() - val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() + temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] + temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] + temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] + temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] + temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] + temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] + temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] + temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] + temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] + temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] + temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] + temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] + temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] + temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] + temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] + temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - matrix[0] = f / imageAspectRatio - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f + matrix[0] = temp[0] + matrix[1] = temp[1] + matrix[2] = temp[2] + matrix[3] = temp[3] + matrix[4] = temp[4] + matrix[5] = temp[5] + matrix[6] = temp[6] + matrix[7] = temp[7] + matrix[8] = temp[8] + matrix[9] = temp[9] + matrix[10] = temp[10] + matrix[11] = temp[11] + matrix[12] = temp[12] + matrix[13] = temp[13] + matrix[14] = temp[14] + matrix[15] = temp[15] + } - matrix[4] = 0.0f - matrix[5] = f - matrix[6] = 0.0f - matrix[7] = 0.0f + fun translate(x: Float, y: Float, z: Float) { + translateMatrix[12] = x + translateMatrix[13] = y + translateMatrix[14] = z - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = -(far + near) / (far - near) - matrix[11] = -1.0f + mul(translateMatrix) + } - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = -(2.0f * far * near) / (far - near) - matrix[15] = 0.0f - } + fun scale(x: Float, y: Float, z: Float) { + scaleMatrix[0] = x + scaleMatrix[5] = y + scaleMatrix[10] = z - fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { - matrix[0] = 2f / (right - left) - matrix[1] = 0f - matrix[2] = 0f - matrix[3] = 0f + mul(scaleMatrix) + } - matrix[4] = 0f - matrix[5] = 2f / (top - bottom) - matrix[6] = 0f - matrix[7] = 0f + fun rotateX(angle: Float) { + rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() + rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() + rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() + rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - matrix[8] = 0f - matrix[9] = 0f - matrix[10] = -2f / (far - near) - matrix[11] = 0f + mul(rotateXMatrix) + } - matrix[12] = - (right + left) / (right - left) - matrix[13] = - (top + bottom) / (top - bottom) - matrix[14] = - (far + near) / (far - near) - matrix[15] = 1f - } + fun rotateY(angle: Float) { + rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() + rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() + rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - fun setToIdentity() { - matrix[0] = 1.0f - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f - matrix[4] = 0.0f - matrix[5] = 1.0f - matrix[6] = 0.0f - matrix[7] = 0.0f - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = 1.0f - matrix[11] = 0.0f - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = 0.0f - matrix[15] = 1.0f - } + mul(rotateYMatrix) + } - fun mul(other: Matrix4) { - mul(other.get()) - } + fun rotateZ(angle: Float) { + rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() + rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() + rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - protected fun mul(other: FloatArray) { - if (other.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } - - temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] - temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] - temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] - temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] - temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] - temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] - temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] - temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] - temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] - temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] - temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] - temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] - temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] - temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] - temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] - temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - - matrix[0] = temp[0] - matrix[1] = temp[1] - matrix[2] = temp[2] - matrix[3] = temp[3] - matrix[4] = temp[4] - matrix[5] = temp[5] - matrix[6] = temp[6] - matrix[7] = temp[7] - matrix[8] = temp[8] - matrix[9] = temp[9] - matrix[10] = temp[10] - matrix[11] = temp[11] - matrix[12] = temp[12] - matrix[13] = temp[13] - matrix[14] = temp[14] - matrix[15] = temp[15] - } - - fun translate(x: Float, y: Float, z: Float) { - translateMatrix[12] = x - translateMatrix[13] = y - translateMatrix[14] = z - - mul(translateMatrix) - } - - fun scale(x: Float, y: Float, z: Float) { - scaleMatrix[0] = x - scaleMatrix[5] = y - scaleMatrix[10] = z - - mul(scaleMatrix) - } - - fun rotateX(angle: Float) { - rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() - rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() - rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() - rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateXMatrix) - } - - fun rotateY(angle: Float) { - rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() - rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() - rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateYMatrix) - } - - fun rotateZ(angle: Float) { - rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() - rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() - rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateZMatrix) - } + mul(rotateZMatrix) + } } diff --git a/src/main/kotlin/games/perses/net/NetUtils.kt b/src/main/kotlin/games/perses/net/NetUtils.kt index 5b5b820..148b920 100644 --- a/src/main/kotlin/games/perses/net/NetUtils.kt +++ b/src/main/kotlin/games/perses/net/NetUtils.kt @@ -9,10 +9,10 @@ */ fun getUrlAsString(url: String): String { - val req = XMLHttpRequest() + val req = XMLHttpRequest() - req.open("GET", url, false) - req.send(null) + req.open("GET", url, false) + req.send(null) - return req.responseText + return req.responseText } diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml index 43edcc2..7ed1494 100644 --- a/.idea/modules/kudens_test.iml +++ b/.idea/modules/kudens_test.iml @@ -1,8 +1,9 @@ - + + $MODULE_DIR$/../../build/kotlinjs/kudens.js \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7ae9969..e7225a0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'perses.games' -version '1.1.6-SNAPSHOT' +version '1.1.7-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'idea' @@ -20,7 +20,7 @@ } buildscript { - ext.kotlin_version = '1.2.21' + ext.kotlin_version = '1.2.30' repositories { maven { url "http://nexus.astraeus.nl/nexus/content/groups/public" diff --git a/src/main/kotlin/games/perses/color/Color.kt b/src/main/kotlin/games/perses/color/Color.kt index 7f235b0..31b540f 100644 --- a/src/main/kotlin/games/perses/color/Color.kt +++ b/src/main/kotlin/games/perses/color/Color.kt @@ -10,107 +10,107 @@ object Color { - /** - * Converts an HSL color value to RGB. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes h, s, and l are contained in the set [0, 1] and - * returns r, g, and b in the set [0, 255]. + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. - * @param h The hue - * * - * @param s The saturation - * * - * @param l The lightness - * * - * @return int array, the RGB representation - */ - fun hslToRgb(h: Float, s: Float, l: Float): IntArray { - val r: Float - val g: Float - val b: Float + * @param h The hue + * * + * @param s The saturation + * * + * @param l The lightness + * * + * @return int array, the RGB representation + */ + fun hslToRgb(h: Float, s: Float, l: Float): IntArray { + val r: Float + val g: Float + val b: Float - if (s == 0f) { - b = l - g = b - r = g // achromatic - } else { - val q = if (l < 0.5f) l * (1 + s) else l + s - l * s - val p = 2 * l - q - r = hueToRgb(p, q, h + 1f / 3f) - g = hueToRgb(p, q, h) - b = hueToRgb(p, q, h - 1f / 3f) - } - val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) + if (s == 0f) { + b = l + g = b + r = g // achromatic + } else { + val q = if (l < 0.5f) l * (1 + s) else l + s - l * s + val p = 2 * l - q + r = hueToRgb(p, q, h + 1f / 3f) + g = hueToRgb(p, q, h) + b = hueToRgb(p, q, h - 1f / 3f) + } + val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) - return rgb + return rgb + } + + /** Helper method that converts hue to rgb */ + fun hueToRgb(p: Float, q: Float, t: Float): Float { + var lt = t + if (lt < 0f) { + lt += 1f + } + if (lt > 1f) { + lt -= 1f + } + if (lt < 1f / 6f) { + return p + (q - p) * 6f * lt + } + if (lt < 1f / 2f) { + return q + } + if (lt < 2f / 3f) { + return p + (q - p) * (2f / 3f - lt) * 6f + } + return p + } + + /** + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes pR, pG, and bpBare contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + + * @param pR The red color value + * * + * @param pG The green color value + * * + * @param pB The blue color value + * * + * @return float array, the HSL representation + */ + fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { + val r = pR / 255f + val g = pG / 255f + val b = pB / 255f + + val max = if (r > g && r > b) r else if (g > b) g else b + val min = if (r < g && r < b) r else if (g < b) g else b + + var h: Float + val s: Float + val l: Float + l = (max + min) / 2.0f + + if (max == min) { + s = 0.0f + h = s + } else { + val d = max - min + s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) + + if (r > g && r > b) + h = (g - b) / d + (if (g < b) 6.0f else 0.0f) + else if (g > b) + h = (b - r) / d + 2.0f + else + h = (r - g) / d + 4.0f + + h /= 6.0f } - /** Helper method that converts hue to rgb */ - fun hueToRgb(p: Float, q: Float, t: Float): Float { - var lt = t - if (lt < 0f) { - lt += 1f - } - if (lt > 1f) { - lt -= 1f - } - if (lt < 1f / 6f) { - return p + (q - p) * 6f * lt - } - if (lt < 1f / 2f) { - return q - } - if (lt < 2f / 3f) { - return p + (q - p) * (2f / 3f - lt) * 6f - } - return p - } - - /** - * Converts an RGB color value to HSL. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes pR, pG, and bpBare contained in the set [0, 255] and - * returns h, s, and l in the set [0, 1]. - - * @param pR The red color value - * * - * @param pG The green color value - * * - * @param pB The blue color value - * * - * @return float array, the HSL representation - */ - fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { - val r = pR / 255f - val g = pG / 255f - val b = pB / 255f - - val max = if (r > g && r > b) r else if (g > b) g else b - val min = if (r < g && r < b) r else if (g < b) g else b - - var h: Float - val s: Float - val l: Float - l = (max + min) / 2.0f - - if (max == min) { - s = 0.0f - h = s - } else { - val d = max - min - s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) - - if (r > g && r > b) - h = (g - b) / d + (if (g < b) 6.0f else 0.0f) - else if (g > b) - h = (b - r) / d + 2.0f - else - h = (r - g) / d + 4.0f - - h /= 6.0f - } - - val hsl = floatArrayOf(h, s, l) - return hsl - } + val hsl = floatArrayOf(h, s, l) + return hsl + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/game/Game.kt b/src/main/kotlin/games/perses/game/Game.kt index 0961316..1becee5 100644 --- a/src/main/kotlin/games/perses/game/Game.kt +++ b/src/main/kotlin/games/perses/game/Game.kt @@ -14,210 +14,210 @@ */ enum class DrawMode { - LINEAR, - NEAREST + LINEAR, + NEAREST } class HTMLElements { - var container: HTMLElement - var webgl: WebGLRenderingContext - var canvas2d: CanvasRenderingContext2D + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D - init { - container = document.createElement("div") as HTMLElement + init { + container = document.createElement("div") as HTMLElement - val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement - val canvas = document.createElement("canvas") as HTMLCanvasElement + val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + val canvas = document.createElement("canvas") as HTMLCanvasElement - container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") - webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" ) - canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" ) + container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;") - document.body!!.appendChild(container) - container.appendChild(webGlCanvas) - container.appendChild(canvas) + document.body!!.appendChild(container) + container.appendChild(webGlCanvas) + container.appendChild(canvas) - val canvas2dcanvas = canvas.getContext("2d") + val canvas2dcanvas = canvas.getContext("2d") - var webglcanvas = webGlCanvas.getContext("webgl") - if (webglcanvas == null) { - console.log("webgl context not found, trying experimental-webgl.") - webglcanvas = webGlCanvas.getContext("experimental-webgl") - } - - if (webglcanvas != null) { - webgl = webglcanvas as WebGLRenderingContext - } else { - console.log("webgl?", webglcanvas) - window.alert("Your browser doesn't seem to support webgl!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } - - if (canvas2dcanvas != null) { - canvas2d = canvas2dcanvas as CanvasRenderingContext2D - } else { - console.log("canvas2d?", canvas2dcanvas) - window.alert("Your browser doesn't seem to support 2d canvas!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } + var webglcanvas = webGlCanvas.getContext("webgl") + if (webglcanvas == null) { + console.log("webgl context not found, trying experimental-webgl.") + webglcanvas = webGlCanvas.getContext("experimental-webgl") } + + if (webglcanvas != null) { + webgl = webglcanvas as WebGLRenderingContext + } else { + console.log("webgl?", webglcanvas) + window.alert("Your browser doesn't seem to support webgl!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + + if (canvas2dcanvas != null) { + canvas2d = canvas2dcanvas as CanvasRenderingContext2D + } else { + console.log("canvas2d?", canvas2dcanvas) + window.alert("Your browser doesn't seem to support 2d canvas!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + } } object Game { - var started = false - val view: View = View() - val html: HTMLElements by lazy { HTMLElements() } - var currentScreen: Screen = DefaultScreen() - var start = Date().getTime() - var currentTime = start - var currentDelta = 0f - var pause: Boolean = false - var clearScreenEveryFrame = true + var started = false + val view: View = View() + val html: HTMLElements by lazy { HTMLElements() } + var currentScreen: Screen = DefaultScreen() + var start = Date().getTime() + var currentTime = start + var currentDelta = 0f + var pause: Boolean = false + var clearScreenEveryFrame = true - var clearRed = 0f - var clearGreen = 0f - var clearBlue = 0f - var clearAlpha = 1f + var clearRed = 0f + var clearGreen = 0f + var clearBlue = 0f + var clearAlpha = 1f - var fps = 0 - var fpsCount = 0 - var fpsCountTime = 0f + var fps = 0 + var fpsCount = 0 + var fpsCountTime = 0f - var borderLeft = 0 - var borderTop = 0 + var borderLeft = 0 + var borderTop = 0 - var focus = true + var focus = true - init { - window.onfocus = { - //println("GOT FOCUS!") + init { + window.onfocus = { + //println("GOT FOCUS!") - focus = true - "" - } - window.onblur = { - //println("LOST FOCUS!") + focus = true + "" + } + window.onblur = { + //println("LOST FOCUS!") - focus = false - "" - } - + focus = false + "" } - fun gl() = html.webgl + } - fun resize() { - val canvas = gl().canvas + fun gl() = html.webgl - // Check if the canvas is not the same size. - val windowWidth = window.innerWidth.toInt() - val windowHeight = window.innerHeight.toInt() + fun resize() { + val canvas = gl().canvas - if (view.lastWindowWidth != windowWidth || - view.lastWindowHeight != windowHeight) { - view.lastWindowWidth = windowWidth - view.lastWindowHeight = windowHeight - view.windowWidth = windowWidth - view.windowHeight = windowHeight + // Check if the canvas is not the same size. + val windowWidth = window.innerWidth.toInt() + val windowHeight = window.innerHeight.toInt() - view.updateView() + if (view.lastWindowWidth != windowWidth || + view.lastWindowHeight != windowHeight) { + view.lastWindowWidth = windowWidth + view.lastWindowHeight = windowHeight + view.windowWidth = windowWidth + view.windowHeight = windowHeight - val textCanvas = html.canvas2d.canvas + view.updateView() - // Make the canvas the same size - canvas.width = view.width.toInt() - canvas.height = view.height.toInt() + val textCanvas = html.canvas2d.canvas - textCanvas.width = view.width.toInt() - textCanvas.height = view.height.toInt() + // Make the canvas the same size + canvas.width = view.width.toInt() + canvas.height = view.height.toInt() - gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) + textCanvas.width = view.width.toInt() + textCanvas.height = view.height.toInt() - borderLeft = (windowWidth - view.windowWidth) / 2 - borderTop = (windowHeight - view.windowHeight) / 2 + gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) - canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) - textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) + borderLeft = (windowWidth - view.windowWidth) / 2 + borderTop = (windowHeight - view.windowHeight) / 2 + + canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + } + } + + fun start(startScreen: Screen) { + if (started) { + throw IllegalStateException("You can only start a game once!") + } + + setScreen(startScreen) + + // start game loop + started = true + gameLoop() + } + + fun setScreen(screen: Screen) { + currentScreen.unloadResources() + + currentScreen = screen + + screen.loadResources() + } + + fun setClearColor(r: Float, g: Float, b: Float, a: Float) { + clearRed = r + clearGreen = g + clearBlue = b + clearAlpha = a + } + + fun gameLoop() { + try { + if (!Textures.ready()) { + gl().clearColor(1f, 1f, 1f, 1f) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } else { + resize() + + if (!pause) { + html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); + + if (clearScreenEveryFrame) { + gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } + + gl().enable(WebGLRenderingContext.BLEND) + gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); + + val time = Date().getTime() + currentDelta = ((time - currentTime) / 1000f).toFloat() + currentTime = time + + val timeInSeconds = (currentTime - start) / 1000f + + fpsCountTime += currentDelta + fpsCount++ + while (fpsCountTime > 1f) { + fps = fpsCount + fpsCountTime -= 1f + fpsCount = 0 + } + + if (focus) { + currentScreen.update(timeInSeconds.toFloat(), currentDelta) + } + + currentScreen.render() } + } + } catch (e: Exception) { + println("Some error...") + console.log(e) } - fun start(startScreen: Screen) { - if (started) { - throw IllegalStateException("You can only start a game once!") - } - - setScreen(startScreen) - - // start game loop - started = true - gameLoop() + window.requestAnimationFrame { + gameLoop() } - - fun setScreen(screen: Screen) { - currentScreen.unloadResources() - - currentScreen = screen - - screen.loadResources() - } - - fun setClearColor(r: Float, g: Float, b: Float, a: Float) { - clearRed = r - clearGreen = g - clearBlue = b - clearAlpha = a - } - - fun gameLoop() { - try { - if (!Textures.ready()) { - gl().clearColor(1f, 1f, 1f, 1f) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } else { - resize() - - if (!pause) { - html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); - - if (clearScreenEveryFrame) { - gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } - - gl().enable(WebGLRenderingContext.BLEND) - gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); - - val time = Date().getTime() - currentDelta = ((time - currentTime) / 1000f).toFloat() - currentTime = time - - val timeInSeconds = (currentTime - start) / 1000f - - fpsCountTime += currentDelta - fpsCount++ - while (fpsCountTime > 1f) { - fps = fpsCount - fpsCountTime -= 1f - fpsCount = 0 - } - - if (focus) { - currentScreen.update(timeInSeconds.toFloat(), currentDelta) - } - - currentScreen.render() - } - } - } catch(e: Exception) { - println("Some error...") - console.log(e) - } - - window.requestAnimationFrame { - gameLoop() - } - } + } } diff --git a/src/main/kotlin/games/perses/game/Screen.kt b/src/main/kotlin/games/perses/game/Screen.kt index 10b6eae..7b381e7 100644 --- a/src/main/kotlin/games/perses/game/Screen.kt +++ b/src/main/kotlin/games/perses/game/Screen.kt @@ -8,31 +8,31 @@ abstract class Screen { - open fun loadResources() {} + open fun loadResources() {} - @Deprecated( + @Deprecated( message = "replace with unloadResources", replaceWith = ReplaceWith("unloadResources()") - ) - open fun closeResources() { - unloadResources() - } + ) + open fun closeResources() { + unloadResources() + } - open fun unloadResources() {} + open fun unloadResources() {} - abstract fun update(time: Float, delta: Float) + abstract fun update(time: Float, delta: Float) - abstract fun render() + abstract fun render() } -class DefaultScreen: Screen() { - override fun update(time: Float, delta: Float) { - } +class DefaultScreen : Screen() { + override fun update(time: Float, delta: Float) { + } - override fun render() { - // show loading message? - Game.gl().clearColor(1f, 1f, 0f, 1f) - Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } + override fun render() { + // show loading message? + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } } diff --git a/src/main/kotlin/games/perses/game/View.kt b/src/main/kotlin/games/perses/game/View.kt index 540a44d..16c9913 100644 --- a/src/main/kotlin/games/perses/game/View.kt +++ b/src/main/kotlin/games/perses/game/View.kt @@ -4,39 +4,39 @@ import kotlin.browser.document enum class ViewType { - PROJECTION, - WIDTH, - HEIGHT, - ABSOLUTE + PROJECTION, + WIDTH, + HEIGHT, + ABSOLUTE } class View( - var lastWindowWidth: Int = 2000, - var lastWindowHeight: Int = 1000, - var windowWidth: Int = 2000, - var windowHeight: Int = 1000, - var width: Float = 1024f, - var height: Float = 1024f, - var angle: Float = 60f, - var near: Float = -0.1f, - var far: Float = -100f, - var minAspectRatio: Float = 1f, - var maxAspectRatio: Float = 1f, - var leftOffset: Int = 0, - var bottomOffset: Int = 0, - var viewType: ViewType = ViewType.WIDTH, - var drawMode: DrawMode = DrawMode.LINEAR) { - var vMatrix = Matrix4() - var aspectRatio = 1f + var lastWindowWidth: Int = 2000, + var lastWindowHeight: Int = 1000, + var windowWidth: Int = 2000, + var windowHeight: Int = 1000, + var width: Float = 1024f, + var height: Float = 1024f, + var angle: Float = 60f, + var near: Float = -0.1f, + var far: Float = -100f, + var minAspectRatio: Float = 1f, + var maxAspectRatio: Float = 1f, + var leftOffset: Int = 0, + var bottomOffset: Int = 0, + var viewType: ViewType = ViewType.WIDTH, + var drawMode: DrawMode = DrawMode.LINEAR) { + var vMatrix = Matrix4() + var aspectRatio = 1f - init { - updateView() - } + init { + updateView() + } - fun requestFullscreen() { - val element = document.body - //language=javascript - js(""" + fun requestFullscreen() { + val element = document.body + //language=javascript + js(""" if(element.requestFullscreen) { element.requestFullscreen(); } else if(element.mozRequestFullScreen) { @@ -47,10 +47,10 @@ element.msRequestFullscreen(); } """) - } + } - fun exitFullscreen() { - js(""" + fun exitFullscreen() { + js(""" if(document.exitFullscreen) { document.exitFullscreen(); } else if(document.mozCancelFullScreen) { @@ -59,178 +59,178 @@ document.webkitExitFullscreen(); } """) + } + + fun switchFullscreen() { + if (isFullscreen()) { + exitFullscreen() + } else { + requestFullscreen() + } + } + + fun isFullscreen(): Boolean { + val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + + return fse != undefined + } + + fun updateView() { + aspectRatio = windowWidth / windowHeight.toFloat() + + if (aspectRatio < minAspectRatio) { + aspectRatio = minAspectRatio + + windowHeight = (windowWidth / aspectRatio).toInt() } - fun switchFullscreen() { - if (isFullscreen()) { - exitFullscreen() - } else { - requestFullscreen() - } + if (aspectRatio > maxAspectRatio) { + aspectRatio = maxAspectRatio + + windowWidth = (windowHeight * aspectRatio).toInt() } - fun isFullscreen(): Boolean { - val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + when (viewType) { + ViewType.ABSOLUTE -> { + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.WIDTH -> { + height = width / aspectRatio - return fse != undefined + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.HEIGHT -> { + width = height * aspectRatio + + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.PROJECTION -> { + vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun updateView() { - aspectRatio = windowWidth / windowHeight.toFloat() + //println("width: $width, height: $height") + } - if (aspectRatio < minAspectRatio) { - aspectRatio = minAspectRatio + fun screenToGameCoordX(screenX: Float): Float { + var result = screenX - windowHeight = (windowWidth / aspectRatio).toInt() - } - - if (aspectRatio > maxAspectRatio) { - aspectRatio = maxAspectRatio - - windowWidth = (windowHeight * aspectRatio).toInt() - } - - when (viewType) { - ViewType.ABSOLUTE -> { - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.WIDTH -> { - height = width / aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.HEIGHT -> { - width = height * aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.PROJECTION -> { - vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } - - //println("width: $width, height: $height") + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = ((screenX - Game.borderLeft) * width / windowWidth) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordX(screenX: Float): Float { - var result = screenX + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( (screenX - Game.borderLeft) * width / windowWidth ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun screenToGameCoordY(screenY: Float): Float { + var result = screenY - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - ((screenY - Game.borderTop) * height / windowHeight) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordY(screenY: Float): Float { - var result = screenY + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( (screenY - Game.borderTop) * height / windowHeight ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordX(gameX: Float): Float { + var result = gameX + val normalizedX = gameX + (width / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = (gameX / width * windowWidth) + Game.borderLeft + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordX(gameX: Float): Float { - var result = gameX - val normalizedX = gameX + (width / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( gameX / width * windowWidth ) + Game.borderLeft - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordY(gameY: Float): Float { + var result = gameY + val normalizedY = gameY + (height / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - (gameY / height * windowHeight) + Game.borderTop + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordY(gameY: Float): Float { - var result = gameY - val normalizedY = gameY + (height / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( gameY / height * windowHeight ) + Game.borderTop - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun setToWidth(width: Float) { + this.width = width + this.viewType = ViewType.WIDTH - return result - } + updateView() + } - fun setToWidth(width: Float) { - this.width = width - this.viewType = ViewType.WIDTH + fun setToHeight(height: Float) { + this.height = height + this.viewType = ViewType.HEIGHT - updateView() - } + updateView() + } - fun setToHeight(height: Float) { - this.height = height - this.viewType = ViewType.HEIGHT + fun setProjection(angle: Float) { + this.angle = angle + this.viewType = ViewType.PROJECTION - updateView() - } + updateView() + } - fun setProjection(angle: Float) { - this.angle = angle - this.viewType = ViewType.PROJECTION + fun setNear(near: Float) { + this.near = near - updateView() - } + updateView() + } - fun setNear(near: Float) { - this.near = near + fun setFar(far: Float) { + this.far = far - updateView() - } - - fun setFar(far: Float) { - this.far = far - - updateView() - } + updateView() + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/input/Input.kt b/src/main/kotlin/games/perses/input/Input.kt index 71a3adc..58c4f23 100644 --- a/src/main/kotlin/games/perses/input/Input.kt +++ b/src/main/kotlin/games/perses/input/Input.kt @@ -15,235 +15,235 @@ */ enum class KeyCode(val keyCode: Int) { - BACKSPACE(8), - TAB(9), - ENTER(13), - SHIFT(16), - CTRL(17), - ALT(18), - PAUSE_BREAK(19), - CAPS_LOCK(20), - ESCAPE(27), - SPACE(32), - PAGE_UP(33), - PAGE_DOWN(34), - END(35), - HOME(36), - LEFT_ARROW(37), - UP_ARROW(38), - RIGHT_ARROW(39), - DOWN_ARROW(40), - INSERT(45), - DELETE(46), - NR_0(48), - NR_1(49), - NR_2(50), - NR_3(51), - NR_4(52), - NR_5(53), - NR_6(54), - NR_7(55), - NR_8(56), - NR_9(57), - A(65), - B(66), - C(67), - D(68), - E(69), - F(70), - G(71), - H(72), - I(73), - J(74), - K(75), - L(76), - M(77), - N(78), - O(79), - P(80), - Q(81), - R(82), - S(83), - T(84), - U(85), - V(86), - W(87), - X(88), - Y(89), - Z(90), - LEFT_WINDOW_KEY(91), - RIGHT_WINDOW_KEY(92), - SELECT_KEY(93), - NUMPAD_0(96), - NUMPAD_1(97), - NUMPAD_2(98), - NUMPAD_3(99), - NUMPAD_4(100), - NUMPAD_5(101), - NUMPAD_6(102), - NUMPAD_7(103), - NUMPAD_8(104), - NUMPAD_9(105), - MULTIPLY(106), - ADD(107), - SUBTRACT(109), - DECIMAL_POINT(110), - DIVIDE(111), - F1(112), - F2(113), - F3(114), - F4(115), - F5(116), - F6(117), - F7(118), - F8(119), - F9(120), - F10(121), - F11(122), - F12(123), - NUM_LOCK(144), - SCROLL_LOCK(145), - SEMI_COLON(186), - EQUAL_SIGN(187), - COMMA(188), - DASH(189), - PERIOD(190), - FORWARD_SLASH(191), - GRAVE_ACCENT(192), - OPEN_BRACKET(219), - BACK_SLASH(220), - CLOSE_BRAKET(221), - SINGLE_QUOTE(222), + BACKSPACE(8), + TAB(9), + ENTER(13), + SHIFT(16), + CTRL(17), + ALT(18), + PAUSE_BREAK(19), + CAPS_LOCK(20), + ESCAPE(27), + SPACE(32), + PAGE_UP(33), + PAGE_DOWN(34), + END(35), + HOME(36), + LEFT_ARROW(37), + UP_ARROW(38), + RIGHT_ARROW(39), + DOWN_ARROW(40), + INSERT(45), + DELETE(46), + NR_0(48), + NR_1(49), + NR_2(50), + NR_3(51), + NR_4(52), + NR_5(53), + NR_6(54), + NR_7(55), + NR_8(56), + NR_9(57), + A(65), + B(66), + C(67), + D(68), + E(69), + F(70), + G(71), + H(72), + I(73), + J(74), + K(75), + L(76), + M(77), + N(78), + O(79), + P(80), + Q(81), + R(82), + S(83), + T(84), + U(85), + V(86), + W(87), + X(88), + Y(89), + Z(90), + LEFT_WINDOW_KEY(91), + RIGHT_WINDOW_KEY(92), + SELECT_KEY(93), + NUMPAD_0(96), + NUMPAD_1(97), + NUMPAD_2(98), + NUMPAD_3(99), + NUMPAD_4(100), + NUMPAD_5(101), + NUMPAD_6(102), + NUMPAD_7(103), + NUMPAD_8(104), + NUMPAD_9(105), + MULTIPLY(106), + ADD(107), + SUBTRACT(109), + DECIMAL_POINT(110), + DIVIDE(111), + F1(112), + F2(113), + F3(114), + F4(115), + F5(116), + F6(117), + F7(118), + F8(119), + F9(120), + F10(121), + F11(122), + F12(123), + NUM_LOCK(144), + SCROLL_LOCK(145), + SEMI_COLON(186), + EQUAL_SIGN(187), + COMMA(188), + DASH(189), + PERIOD(190), + FORWARD_SLASH(191), + GRAVE_ACCENT(192), + OPEN_BRACKET(219), + BACK_SLASH(220), + CLOSE_BRAKET(221), + SINGLE_QUOTE(222), - ESC(27), - LEFT(37), - UP(38), - DOWN(40), - RIGHT(39), - MINUS(109), - PLUS(107), + ESC(27), + LEFT(37), + UP(38), + DOWN(40), + RIGHT(39), + MINUS(109), + PLUS(107), } interface InputProcessor { - fun keyPressed(charCode: Int) + fun keyPressed(charCode: Int) - fun keyDown(keyCode: Int) + fun keyDown(keyCode: Int) - fun keyUp(keyCode: Int) + fun keyUp(keyCode: Int) - fun pointerClick(pointer: Int, x: Float, y: Float) + fun pointerClick(pointer: Int, x: Float, y: Float) - fun mouseMove(x: Float, y: Float) + fun mouseMove(x: Float, y: Float) } open class EmptyInputProcessor : InputProcessor { - override fun pointerClick(pointer: Int, x: Float, y: Float) { } + override fun pointerClick(pointer: Int, x: Float, y: Float) {} - override fun keyDown(keyCode: Int) { } + override fun keyDown(keyCode: Int) {} - override fun keyPressed(charCode: Int) { } + override fun keyPressed(charCode: Int) {} - override fun keyUp(keyCode: Int) { } + override fun keyUp(keyCode: Int) {} - override fun mouseMove(x: Float, y: Float) { } + override fun mouseMove(x: Float, y: Float) {} } object Input { - private val keys: MutableMap = HashMap() - private var inputProcesser: InputProcessor = EmptyInputProcessor() + private val keys: MutableMap = HashMap() + private var inputProcesser: InputProcessor = EmptyInputProcessor() - init { - val body = document.body - if (body != null) { - body.onkeydown = { - keyDown(it) - } + init { + val body = document.body + if (body != null) { + body.onkeydown = { + keyDown(it) + } - body.onkeyup = { - keyUp(it) - } + body.onkeyup = { + keyUp(it) + } - body.onkeypress = { - keyPress(it) - } + body.onkeypress = { + keyPress(it) + } - body.onclick = { - mouseClick(it) - } + body.onclick = { + mouseClick(it) + } - body.onmousedown = { - mouseMove(it) - } + body.onmousedown = { + mouseMove(it) + } - body.onmouseup = { - mouseMove(it) - } + body.onmouseup = { + mouseMove(it) + } - body.onmousemove = { - mouseMove(it) - } - } else { - console.log("Can't register key events, document.body is null!?") - } + body.onmousemove = { + mouseMove(it) + } + } else { + console.log("Can't register key events, document.body is null!?") } + } - fun setInputProcessor(processor: InputProcessor) { - this.inputProcesser = processor + fun setInputProcessor(processor: InputProcessor) { + this.inputProcesser = processor + } + + private fun keyDown(key: Event) { + if (key is KeyboardEvent) { + keys.put(key.keyCode, Date().getTime()) + + inputProcesser.keyDown(key.keyCode) } + } - private fun keyDown(key: Event) { - if (key is KeyboardEvent) { - keys.put(key.keyCode, Date().getTime()) + private fun keyUp(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyUp(key.keyCode) - inputProcesser.keyDown(key.keyCode) - } + keys.remove(key.keyCode) } + } - private fun keyUp(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyUp(key.keyCode) - - keys.remove(key.keyCode) - } + private fun keyPress(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyPressed(key.charCode) } + } - private fun keyPress(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyPressed(key.charCode) - } + private fun mouseClick(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + + inputProcesser.pointerClick(event.button.toInt(), vx, vy) } + } - private fun mouseClick(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + private fun mouseMove(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) - inputProcesser.pointerClick(event.button.toInt(), vx, vy) - } + inputProcesser.mouseMove(vx, vy) } + } - private fun mouseMove(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + fun isDown(keyCode: Int) = keys.containsKey(keyCode) - inputProcesser.mouseMove(vx, vy) - } - } + fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - fun isDown(keyCode: Int) = keys.containsKey(keyCode) + fun wasPressed(keyCode: Int, delta: Double): Boolean { + val time = keys[keyCode] - fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - - fun wasPressed(keyCode: Int, delta: Double): Boolean { - val time = keys[keyCode] - - return (time != null && time > (Date().getTime() - delta)) - } + return (time != null && time > (Date().getTime() - delta)) + } } diff --git a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt index f1c7808..f3d4126 100644 --- a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt +++ b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt @@ -11,201 +11,201 @@ */ class MapData { - var version: Int = 1 - var properties: MutableMap = HashMap() - var layers: Array? = null - var tilesets: Array? = null + var version: Int = 1 + var properties: MutableMap = HashMap() + var layers: Array? = null + var tilesets: Array? = null - var height: Int = 0 - var width: Int = 0 + var height: Int = 0 + var width: Int = 0 - var nextobjectid: Int = 0 - var orientation: String = "orthogonal" - var renderorder: String = "right-down" - var tileheight: Int = 0 - var tilewidth: Int = 0 + var nextobjectid: Int = 0 + var orientation: String = "orthogonal" + var renderorder: String = "right-down" + var tileheight: Int = 0 + var tilewidth: Int = 0 } class MapLayer { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var data: Array? = null - var encoding: String = "" - var x: Int = 0 - var y: Int = 0 - var width: Int = 0 - var height: Int = 0 - var name: String = "" - var opacity: Float = 1f - var type: String = "" - var visible: Boolean = true - var draworder: String = "" + var data: Array? = null + var encoding: String = "" + var x: Int = 0 + var y: Int = 0 + var width: Int = 0 + var height: Int = 0 + var name: String = "" + var opacity: Float = 1f + var type: String = "" + var visible: Boolean = true + var draworder: String = "" } class MapTileset { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var firstgid: Int = 0 - var image: String = "" - var imageheight: Int = 0 - var imagewidth: Int = 0 - var margin: Int = 0 - var name: String = "" - var spacing: Int = 0 - var tilecount: Int = 0 - var tileheight: Int = 0 - var tilewidth: Int = 0 - var tileproperties: MutableMap> = HashMap() + var firstgid: Int = 0 + var image: String = "" + var imageheight: Int = 0 + var imagewidth: Int = 0 + var margin: Int = 0 + var name: String = "" + var spacing: Int = 0 + var tilecount: Int = 0 + var tileheight: Int = 0 + var tilewidth: Int = 0 + var tileproperties: MutableMap> = HashMap() } class TilesetIndex( - val texture: Texture?, - val tcLeft: Float, - val tcTop: Float, - val tcRight: Float, - val tcBottom: Float, - val scale: Float - ) { - constructor() : this(null, 0f, 0f, 0f, 0f, 0f) + val texture: Texture?, + val tcLeft: Float, + val tcTop: Float, + val tcRight: Float, + val tcBottom: Float, + val scale: Float +) { + constructor() : this(null, 0f, 0f, 0f, 0f, 0f) - fun render(x: Float, y: Float) { - texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) - } + fun render(x: Float, y: Float) { + texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) + } } class TiledMap(dir: String = "", url: String) { - val properties: Map = HashMap() - val data: MapData - val tileset: Array - val tiles: Array - var first = true - //var tilesetIndex: Array = Array(0, { TilesetIndex() }) + val properties: Map = HashMap() + val data: MapData + val tileset: Array + val tiles: Array + var first = true + //var tilesetIndex: Array = Array(0, { TilesetIndex() }) - init { - var tileDir = dir - if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { - tileDir = tileDir + "/" - } - - data = JSON.parse(getUrlAsString(tileDir + url)) - //println("map data is loaded") - val tilesets = data.tilesets - if (tilesets != null) { - tileset = Array(tilesets.size, { "" }) - var maxGid = 0 - for (index in 0..tilesets.size - 1) { - tileset[index] = tilesets[index].name - Textures.load(tilesets[index].name, tileDir + tilesets[index].image) - maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) - } - - tiles = Array(maxGid, { TilesetIndex() }) - } else { - tileset = Array(0, { "" }) - tiles = Array(0, { TilesetIndex() }) - } - - cacheTiles() + init { + var tileDir = dir + if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { + tileDir = tileDir + "/" } - fun cacheTiles() { - if (!Textures.ready()) { - window.setTimeout({ cacheTiles() }, 10) - } else { - val tilesets = data.tilesets - var tcLeft = 0f - var tcTop = 0f - var tcRight = 0f - var tcBottom = 0f + data = JSON.parse(getUrlAsString(tileDir + url)) + //println("map data is loaded") + val tilesets = data.tilesets + if (tilesets != null) { + tileset = Array(tilesets.size, { "" }) + var maxGid = 0 + for (index in 0..tilesets.size - 1) { + tileset[index] = tilesets[index].name + Textures.load(tilesets[index].name, tileDir + tilesets[index].image) + maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) + } - if (tilesets != null) { - - - for (tileset in tilesets) { - val tilesHor = tileset.imagewidth / tileset.tilewidth - val tilesVer = tileset.imageheight / tileset.tileheight - val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) - - for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { - val texture = Textures.get(tileset.name) - - val gid = index - tileset.firstgid - - val xi = gid % tilesHor - var yi = gid / tilesHor - yi = tilesVer - yi - 1 - val tw = 1f / tilesHor.toFloat() - val th = 1f / tilesVer.toFloat() - - val pixelW = 0.1f / tileset.tilewidth - val pixelH = 0.1f / tileset.tileheight - - tcLeft = xi * tw - tcRight = tcLeft + tw - - // switch up/down because of texture coord 0,0 in left bottom corner - tcBottom = yi * th - tcTop = tcBottom + th - - tcLeft += pixelW - tcRight -= pixelW - - tcBottom += pixelH - tcTop -= pixelH - - tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) - } - } - } - } + tiles = Array(maxGid, { TilesetIndex() }) + } else { + tileset = Array(0, { "" }) + tiles = Array(0, { TilesetIndex() }) } - fun drawTile(tile: Int, x: Float, y: Float) { - tiles[tile].render(x, y) + cacheTiles() + } + + fun cacheTiles() { + if (!Textures.ready()) { + window.setTimeout({ cacheTiles() }, 10) + } else { + val tilesets = data.tilesets + var tcLeft = 0f + var tcTop = 0f + var tcRight = 0f + var tcBottom = 0f + + if (tilesets != null) { + + + for (tileset in tilesets) { + val tilesHor = tileset.imagewidth / tileset.tilewidth + val tilesVer = tileset.imageheight / tileset.tileheight + val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) + + for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { + val texture = Textures.get(tileset.name) + + val gid = index - tileset.firstgid + + val xi = gid % tilesHor + var yi = gid / tilesHor + yi = tilesVer - yi - 1 + val tw = 1f / tilesHor.toFloat() + val th = 1f / tilesVer.toFloat() + + val pixelW = 0.1f / tileset.tilewidth + val pixelH = 0.1f / tileset.tileheight + + tcLeft = xi * tw + tcRight = tcLeft + tw + + // switch up/down because of texture coord 0,0 in left bottom corner + tcBottom = yi * th + tcTop = tcBottom + th + + tcLeft += pixelW + tcRight -= pixelW + + tcBottom += pixelH + tcTop -= pixelH + + tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) + } + } + } + } + } + + fun drawTile(tile: Int, x: Float, y: Float) { + tiles[tile].render(x, y) + } + + fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { + var x = 0f + var y = 0f + val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") + val layer = layers[layerIndex] + + val layerData = layer.data + if (layerData != null) { + for (index in layerData.indices) { + // todo: determine if in view + // todo: determine tilewidth + //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { + drawTile(layerData[index], xo + x * 128f, yo + y * 128f) + + when (data.renderorder) { + "right-down" -> { + x++ + if (x >= layer.width) { + x = 0f + y-- + } + } + else -> { + throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") + } + } + //} + } } - fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { - var x = 0f - var y = 0f - val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") - val layer = layers[layerIndex] + val tilesets = data.tilesets + if (tilesets != null) { + for (tileset in tilesets) { + if (Textures.has(tileset.name)) { + val tx = Textures.get(tileset.name) - val layerData = layer.data - if (layerData != null) { - for (index in layerData.indices) { - // todo: determine if in view - // todo: determine tilewidth - //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { - drawTile(layerData[index], xo + x * 128f, yo + y * 128f) - - when (data.renderorder) { - "right-down" -> { - x++ - if (x >= layer.width) { - x = 0f - y-- - } - } - else -> { - throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") - } - } - //} - } + tx.render() } - - val tilesets = data.tilesets - if (tilesets != null) { - for (tileset in tilesets) { - if (Textures.has(tileset.name)) { - val tx = Textures.get(tileset.name) - - tx.render() - } - } - } - - - first = false + } } + + + first = false + } } diff --git a/src/main/kotlin/games/perses/math/Matrix4.kt b/src/main/kotlin/games/perses/math/Matrix4.kt index 7da03cd..bd274bf 100644 --- a/src/main/kotlin/games/perses/math/Matrix4.kt +++ b/src/main/kotlin/games/perses/math/Matrix4.kt @@ -10,184 +10,184 @@ */ class Matrix4 { - internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - internal var temp = FloatArray(16) + internal var temp = FloatArray(16) - private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - fun get(): FloatArray { - return matrix + fun get(): FloatArray { + return matrix + } + + fun getFloat32Array() = Float32Array(get().toTypedArray()) + + fun set(values: FloatArray) { + if (values.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun getFloat32Array() = Float32Array(get().toTypedArray()) + matrix = values + } - fun set(values: FloatArray) { - if (values.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } + fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { + val r = (angle / 180f * Math.PI).toFloat() + val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() - matrix = values + matrix[0] = f / imageAspectRatio + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + + matrix[4] = 0.0f + matrix[5] = f + matrix[6] = 0.0f + matrix[7] = 0.0f + + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = -(far + near) / (far - near) + matrix[11] = -1.0f + + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = -(2.0f * far * near) / (far - near) + matrix[15] = 0.0f + } + + fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { + matrix[0] = 2f / (right - left) + matrix[1] = 0f + matrix[2] = 0f + matrix[3] = 0f + + matrix[4] = 0f + matrix[5] = 2f / (top - bottom) + matrix[6] = 0f + matrix[7] = 0f + + matrix[8] = 0f + matrix[9] = 0f + matrix[10] = -2f / (far - near) + matrix[11] = 0f + + matrix[12] = -(right + left) / (right - left) + matrix[13] = -(top + bottom) / (top - bottom) + matrix[14] = -(far + near) / (far - near) + matrix[15] = 1f + } + + fun setToIdentity() { + matrix[0] = 1.0f + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + matrix[4] = 0.0f + matrix[5] = 1.0f + matrix[6] = 0.0f + matrix[7] = 0.0f + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = 1.0f + matrix[11] = 0.0f + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = 0.0f + matrix[15] = 1.0f + } + + fun mul(other: Matrix4) { + mul(other.get()) + } + + protected fun mul(other: FloatArray) { + if (other.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { - val r = (angle / 180f * Math.PI).toFloat() - val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() + temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] + temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] + temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] + temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] + temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] + temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] + temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] + temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] + temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] + temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] + temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] + temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] + temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] + temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] + temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] + temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - matrix[0] = f / imageAspectRatio - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f + matrix[0] = temp[0] + matrix[1] = temp[1] + matrix[2] = temp[2] + matrix[3] = temp[3] + matrix[4] = temp[4] + matrix[5] = temp[5] + matrix[6] = temp[6] + matrix[7] = temp[7] + matrix[8] = temp[8] + matrix[9] = temp[9] + matrix[10] = temp[10] + matrix[11] = temp[11] + matrix[12] = temp[12] + matrix[13] = temp[13] + matrix[14] = temp[14] + matrix[15] = temp[15] + } - matrix[4] = 0.0f - matrix[5] = f - matrix[6] = 0.0f - matrix[7] = 0.0f + fun translate(x: Float, y: Float, z: Float) { + translateMatrix[12] = x + translateMatrix[13] = y + translateMatrix[14] = z - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = -(far + near) / (far - near) - matrix[11] = -1.0f + mul(translateMatrix) + } - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = -(2.0f * far * near) / (far - near) - matrix[15] = 0.0f - } + fun scale(x: Float, y: Float, z: Float) { + scaleMatrix[0] = x + scaleMatrix[5] = y + scaleMatrix[10] = z - fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { - matrix[0] = 2f / (right - left) - matrix[1] = 0f - matrix[2] = 0f - matrix[3] = 0f + mul(scaleMatrix) + } - matrix[4] = 0f - matrix[5] = 2f / (top - bottom) - matrix[6] = 0f - matrix[7] = 0f + fun rotateX(angle: Float) { + rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() + rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() + rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() + rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - matrix[8] = 0f - matrix[9] = 0f - matrix[10] = -2f / (far - near) - matrix[11] = 0f + mul(rotateXMatrix) + } - matrix[12] = - (right + left) / (right - left) - matrix[13] = - (top + bottom) / (top - bottom) - matrix[14] = - (far + near) / (far - near) - matrix[15] = 1f - } + fun rotateY(angle: Float) { + rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() + rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() + rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - fun setToIdentity() { - matrix[0] = 1.0f - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f - matrix[4] = 0.0f - matrix[5] = 1.0f - matrix[6] = 0.0f - matrix[7] = 0.0f - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = 1.0f - matrix[11] = 0.0f - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = 0.0f - matrix[15] = 1.0f - } + mul(rotateYMatrix) + } - fun mul(other: Matrix4) { - mul(other.get()) - } + fun rotateZ(angle: Float) { + rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() + rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() + rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - protected fun mul(other: FloatArray) { - if (other.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } - - temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] - temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] - temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] - temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] - temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] - temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] - temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] - temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] - temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] - temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] - temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] - temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] - temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] - temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] - temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] - temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - - matrix[0] = temp[0] - matrix[1] = temp[1] - matrix[2] = temp[2] - matrix[3] = temp[3] - matrix[4] = temp[4] - matrix[5] = temp[5] - matrix[6] = temp[6] - matrix[7] = temp[7] - matrix[8] = temp[8] - matrix[9] = temp[9] - matrix[10] = temp[10] - matrix[11] = temp[11] - matrix[12] = temp[12] - matrix[13] = temp[13] - matrix[14] = temp[14] - matrix[15] = temp[15] - } - - fun translate(x: Float, y: Float, z: Float) { - translateMatrix[12] = x - translateMatrix[13] = y - translateMatrix[14] = z - - mul(translateMatrix) - } - - fun scale(x: Float, y: Float, z: Float) { - scaleMatrix[0] = x - scaleMatrix[5] = y - scaleMatrix[10] = z - - mul(scaleMatrix) - } - - fun rotateX(angle: Float) { - rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() - rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() - rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() - rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateXMatrix) - } - - fun rotateY(angle: Float) { - rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() - rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() - rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateYMatrix) - } - - fun rotateZ(angle: Float) { - rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() - rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() - rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateZMatrix) - } + mul(rotateZMatrix) + } } diff --git a/src/main/kotlin/games/perses/net/NetUtils.kt b/src/main/kotlin/games/perses/net/NetUtils.kt index 5b5b820..148b920 100644 --- a/src/main/kotlin/games/perses/net/NetUtils.kt +++ b/src/main/kotlin/games/perses/net/NetUtils.kt @@ -9,10 +9,10 @@ */ fun getUrlAsString(url: String): String { - val req = XMLHttpRequest() + val req = XMLHttpRequest() - req.open("GET", url, false) - req.send(null) + req.open("GET", url, false) + req.send(null) - return req.responseText + return req.responseText } diff --git a/src/main/kotlin/games/perses/shader/ShaderProgram.kt b/src/main/kotlin/games/perses/shader/ShaderProgram.kt index cf07c0f..7dde03a 100644 --- a/src/main/kotlin/games/perses/shader/ShaderProgram.kt +++ b/src/main/kotlin/games/perses/shader/ShaderProgram.kt @@ -1,6 +1,10 @@ package games.perses.shader -import org.khronos.webgl.* +import org.khronos.webgl.Float32Array +import org.khronos.webgl.WebGLBuffer +import org.khronos.webgl.WebGLProgram +import org.khronos.webgl.WebGLRenderingContext +import org.khronos.webgl.WebGLShader /** * User: rnentjes @@ -9,103 +13,125 @@ */ class ShaderProgram( - val webgl: WebGLRenderingContext, - val drawType: Int, - vertexShaderSource: String, - fragmentShaderSource: String, - val vainfo: Array, - val setter: (program: ShaderProgram, data: T) -> Unit) { + val webgl: WebGLRenderingContext, + val drawType: Int, + vertexShaderSource: String, + fragmentShaderSource: String, + val vainfo: Array, + val setter: (program: ShaderProgram, data: T) -> Unit +) { - var shaderProgram: WebGLProgram - var vertex: WebGLShader - var fragment: WebGLShader + var shaderProgram: WebGLProgram + var vertex: WebGLShader + var fragment: WebGLShader - var verticesBlockSize = 0 - var drawLength = 0 + var verticesBlockSize = 0 + var drawLength = 0 - init { - vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER) - fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER) + init { + vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER) + fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER) - shaderProgram = webgl.createProgram() ?: throw IllegalStateException("Unable to request shader program from webgl context!") - webgl.attachShader(shaderProgram, vertex) - webgl.attachShader(shaderProgram, fragment) - webgl.linkProgram(shaderProgram) + shaderProgram = webgl.createProgram() ?: throw IllegalStateException( + "Unable to request shader program from webgl context!" + ) + webgl.attachShader(shaderProgram, vertex) + webgl.attachShader(shaderProgram, fragment) + webgl.linkProgram(shaderProgram) - if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) { - //println(webgl.getProgramInfoLog(shaderProgram)) - throw IllegalStateException("Unable to compile shader program!") - } - - webgl.useProgram(shaderProgram) - - this.verticesBlockSize = 0 - - // set attribute locations... - for (info in vainfo.iterator()) { - info.location = webgl.getAttribLocation(shaderProgram, info.locationName) - info.offset = verticesBlockSize - - verticesBlockSize += info.numElements - //println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}") - } - - when(drawType) { - WebGLRenderingContext.TRIANGLES -> { - drawLength = verticesBlockSize * 3 - } - else -> { - drawLength = verticesBlockSize - } - } - - //println("verticesBlockSize $verticesBlockSize") - - //println("ShaderProgram constructor done") + if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) { + //println(webgl.getProgramInfoLog(shaderProgram)) + throw IllegalStateException("Unable to compile shader program!") } - private fun compileShader(source: String, type: Int): WebGLShader { - val result: WebGLShader = webgl.createShader(type) ?: throw IllegalStateException("Unable to request shader from webgl context!") + webgl.useProgram(shaderProgram) - webgl.shaderSource(result, source) - webgl.compileShader(result) + this.verticesBlockSize = 0 - if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) { - throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}") - } + // set attribute locations... + for (info in vainfo.iterator()) { + info.location = webgl.getAttribLocation(shaderProgram, info.locationName) + info.offset = verticesBlockSize - return result + verticesBlockSize += info.numElements + //println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}") } - fun begin(attribBuffer: WebGLBuffer, userdata: T) { - webgl.useProgram(shaderProgram); - webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); - - // set attribute locations... - for (info in vainfo.iterator()) { - webgl.enableVertexAttribArray(info.location) - webgl.vertexAttribPointer(info.location, info.numElements, WebGLRenderingContext.FLOAT, false, verticesBlockSize * 4, info.offset * 4) - } - - setter(this, userdata) + when (drawType) { + WebGLRenderingContext.TRIANGLES -> { + drawLength = verticesBlockSize * 3 + } + else -> { + drawLength = verticesBlockSize + } } - fun end() { - for (info in vainfo.iterator()) { - webgl.disableVertexAttribArray(info.location); - } - webgl.useProgram(null) + //println("verticesBlockSize $verticesBlockSize") + + //println("ShaderProgram constructor done") + } + + private fun compileShader(source: String, type: Int): WebGLShader { + val result: WebGLShader = webgl.createShader(type) + ?: throw IllegalStateException("Unable to request shader from webgl context!") + + webgl.shaderSource(result, source) + webgl.compileShader(result) + + if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) { + throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}") } - fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location); + return result + } - fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location); + fun begin(attribBuffer: WebGLBuffer, userdata: T) { + webgl.useProgram(shaderProgram); + webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); - fun setUniform1f(location: String, value: Float) { webgl.uniform1f(getUniformLocation(location), value); } - fun setUniform2f(location: String, v1: Float, v2: Float) { webgl.uniform2f(getUniformLocation(location), v1, v2); } - fun setUniform3f(location: String, v1: Float, v2: Float, v3: Float) { webgl.uniform3f(getUniformLocation(location), v1, v2, v3); } - fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); } - fun setUniform1i(location: String, value: Int) { webgl.uniform1i(getUniformLocation(location), value); } - fun setUniformMatrix4fv(location: String, value: Float32Array) { webgl.uniformMatrix4fv(getUniformLocation(location), false, value); } + // set attribute locations... + for (info in vainfo.iterator()) { + webgl.enableVertexAttribArray(info.location) + webgl.vertexAttribPointer( + info.location, + info.numElements, + WebGLRenderingContext.FLOAT, + false, + verticesBlockSize * 4, + info.offset * 4 + ) + } + + setter(this, userdata) + } + + fun end() { + for (info in vainfo.iterator()) { + webgl.disableVertexAttribArray(info.location); + } + webgl.useProgram(null) + } + + fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location); + + fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location); + + fun setUniform1f(location: String, value: Float) { + webgl.uniform1f(getUniformLocation(location), value); } + + fun setUniform2f(location: String, v1: Float, v2: Float) { + webgl.uniform2f(getUniformLocation(location), v1, v2); } + + fun setUniform3f(location: String, v1: Float, v2: Float, v3: Float) { + webgl.uniform3f(getUniformLocation(location), v1, v2, v3); } + + fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { + webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); } + + fun setUniform1i(location: String, value: Int) { + webgl.uniform1i(getUniformLocation(location), value); } + + fun setUniformMatrix4fv(location: String, value: Float32Array) { + webgl.uniformMatrix4fv(getUniformLocation(location), false, value); } } diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml index 43edcc2..7ed1494 100644 --- a/.idea/modules/kudens_test.iml +++ b/.idea/modules/kudens_test.iml @@ -1,8 +1,9 @@ - + + $MODULE_DIR$/../../build/kotlinjs/kudens.js \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7ae9969..e7225a0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'perses.games' -version '1.1.6-SNAPSHOT' +version '1.1.7-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'idea' @@ -20,7 +20,7 @@ } buildscript { - ext.kotlin_version = '1.2.21' + ext.kotlin_version = '1.2.30' repositories { maven { url "http://nexus.astraeus.nl/nexus/content/groups/public" diff --git a/src/main/kotlin/games/perses/color/Color.kt b/src/main/kotlin/games/perses/color/Color.kt index 7f235b0..31b540f 100644 --- a/src/main/kotlin/games/perses/color/Color.kt +++ b/src/main/kotlin/games/perses/color/Color.kt @@ -10,107 +10,107 @@ object Color { - /** - * Converts an HSL color value to RGB. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes h, s, and l are contained in the set [0, 1] and - * returns r, g, and b in the set [0, 255]. + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. - * @param h The hue - * * - * @param s The saturation - * * - * @param l The lightness - * * - * @return int array, the RGB representation - */ - fun hslToRgb(h: Float, s: Float, l: Float): IntArray { - val r: Float - val g: Float - val b: Float + * @param h The hue + * * + * @param s The saturation + * * + * @param l The lightness + * * + * @return int array, the RGB representation + */ + fun hslToRgb(h: Float, s: Float, l: Float): IntArray { + val r: Float + val g: Float + val b: Float - if (s == 0f) { - b = l - g = b - r = g // achromatic - } else { - val q = if (l < 0.5f) l * (1 + s) else l + s - l * s - val p = 2 * l - q - r = hueToRgb(p, q, h + 1f / 3f) - g = hueToRgb(p, q, h) - b = hueToRgb(p, q, h - 1f / 3f) - } - val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) + if (s == 0f) { + b = l + g = b + r = g // achromatic + } else { + val q = if (l < 0.5f) l * (1 + s) else l + s - l * s + val p = 2 * l - q + r = hueToRgb(p, q, h + 1f / 3f) + g = hueToRgb(p, q, h) + b = hueToRgb(p, q, h - 1f / 3f) + } + val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) - return rgb + return rgb + } + + /** Helper method that converts hue to rgb */ + fun hueToRgb(p: Float, q: Float, t: Float): Float { + var lt = t + if (lt < 0f) { + lt += 1f + } + if (lt > 1f) { + lt -= 1f + } + if (lt < 1f / 6f) { + return p + (q - p) * 6f * lt + } + if (lt < 1f / 2f) { + return q + } + if (lt < 2f / 3f) { + return p + (q - p) * (2f / 3f - lt) * 6f + } + return p + } + + /** + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes pR, pG, and bpBare contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + + * @param pR The red color value + * * + * @param pG The green color value + * * + * @param pB The blue color value + * * + * @return float array, the HSL representation + */ + fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { + val r = pR / 255f + val g = pG / 255f + val b = pB / 255f + + val max = if (r > g && r > b) r else if (g > b) g else b + val min = if (r < g && r < b) r else if (g < b) g else b + + var h: Float + val s: Float + val l: Float + l = (max + min) / 2.0f + + if (max == min) { + s = 0.0f + h = s + } else { + val d = max - min + s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) + + if (r > g && r > b) + h = (g - b) / d + (if (g < b) 6.0f else 0.0f) + else if (g > b) + h = (b - r) / d + 2.0f + else + h = (r - g) / d + 4.0f + + h /= 6.0f } - /** Helper method that converts hue to rgb */ - fun hueToRgb(p: Float, q: Float, t: Float): Float { - var lt = t - if (lt < 0f) { - lt += 1f - } - if (lt > 1f) { - lt -= 1f - } - if (lt < 1f / 6f) { - return p + (q - p) * 6f * lt - } - if (lt < 1f / 2f) { - return q - } - if (lt < 2f / 3f) { - return p + (q - p) * (2f / 3f - lt) * 6f - } - return p - } - - /** - * Converts an RGB color value to HSL. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes pR, pG, and bpBare contained in the set [0, 255] and - * returns h, s, and l in the set [0, 1]. - - * @param pR The red color value - * * - * @param pG The green color value - * * - * @param pB The blue color value - * * - * @return float array, the HSL representation - */ - fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { - val r = pR / 255f - val g = pG / 255f - val b = pB / 255f - - val max = if (r > g && r > b) r else if (g > b) g else b - val min = if (r < g && r < b) r else if (g < b) g else b - - var h: Float - val s: Float - val l: Float - l = (max + min) / 2.0f - - if (max == min) { - s = 0.0f - h = s - } else { - val d = max - min - s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) - - if (r > g && r > b) - h = (g - b) / d + (if (g < b) 6.0f else 0.0f) - else if (g > b) - h = (b - r) / d + 2.0f - else - h = (r - g) / d + 4.0f - - h /= 6.0f - } - - val hsl = floatArrayOf(h, s, l) - return hsl - } + val hsl = floatArrayOf(h, s, l) + return hsl + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/game/Game.kt b/src/main/kotlin/games/perses/game/Game.kt index 0961316..1becee5 100644 --- a/src/main/kotlin/games/perses/game/Game.kt +++ b/src/main/kotlin/games/perses/game/Game.kt @@ -14,210 +14,210 @@ */ enum class DrawMode { - LINEAR, - NEAREST + LINEAR, + NEAREST } class HTMLElements { - var container: HTMLElement - var webgl: WebGLRenderingContext - var canvas2d: CanvasRenderingContext2D + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D - init { - container = document.createElement("div") as HTMLElement + init { + container = document.createElement("div") as HTMLElement - val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement - val canvas = document.createElement("canvas") as HTMLCanvasElement + val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + val canvas = document.createElement("canvas") as HTMLCanvasElement - container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") - webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" ) - canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" ) + container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;") - document.body!!.appendChild(container) - container.appendChild(webGlCanvas) - container.appendChild(canvas) + document.body!!.appendChild(container) + container.appendChild(webGlCanvas) + container.appendChild(canvas) - val canvas2dcanvas = canvas.getContext("2d") + val canvas2dcanvas = canvas.getContext("2d") - var webglcanvas = webGlCanvas.getContext("webgl") - if (webglcanvas == null) { - console.log("webgl context not found, trying experimental-webgl.") - webglcanvas = webGlCanvas.getContext("experimental-webgl") - } - - if (webglcanvas != null) { - webgl = webglcanvas as WebGLRenderingContext - } else { - console.log("webgl?", webglcanvas) - window.alert("Your browser doesn't seem to support webgl!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } - - if (canvas2dcanvas != null) { - canvas2d = canvas2dcanvas as CanvasRenderingContext2D - } else { - console.log("canvas2d?", canvas2dcanvas) - window.alert("Your browser doesn't seem to support 2d canvas!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } + var webglcanvas = webGlCanvas.getContext("webgl") + if (webglcanvas == null) { + console.log("webgl context not found, trying experimental-webgl.") + webglcanvas = webGlCanvas.getContext("experimental-webgl") } + + if (webglcanvas != null) { + webgl = webglcanvas as WebGLRenderingContext + } else { + console.log("webgl?", webglcanvas) + window.alert("Your browser doesn't seem to support webgl!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + + if (canvas2dcanvas != null) { + canvas2d = canvas2dcanvas as CanvasRenderingContext2D + } else { + console.log("canvas2d?", canvas2dcanvas) + window.alert("Your browser doesn't seem to support 2d canvas!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + } } object Game { - var started = false - val view: View = View() - val html: HTMLElements by lazy { HTMLElements() } - var currentScreen: Screen = DefaultScreen() - var start = Date().getTime() - var currentTime = start - var currentDelta = 0f - var pause: Boolean = false - var clearScreenEveryFrame = true + var started = false + val view: View = View() + val html: HTMLElements by lazy { HTMLElements() } + var currentScreen: Screen = DefaultScreen() + var start = Date().getTime() + var currentTime = start + var currentDelta = 0f + var pause: Boolean = false + var clearScreenEveryFrame = true - var clearRed = 0f - var clearGreen = 0f - var clearBlue = 0f - var clearAlpha = 1f + var clearRed = 0f + var clearGreen = 0f + var clearBlue = 0f + var clearAlpha = 1f - var fps = 0 - var fpsCount = 0 - var fpsCountTime = 0f + var fps = 0 + var fpsCount = 0 + var fpsCountTime = 0f - var borderLeft = 0 - var borderTop = 0 + var borderLeft = 0 + var borderTop = 0 - var focus = true + var focus = true - init { - window.onfocus = { - //println("GOT FOCUS!") + init { + window.onfocus = { + //println("GOT FOCUS!") - focus = true - "" - } - window.onblur = { - //println("LOST FOCUS!") + focus = true + "" + } + window.onblur = { + //println("LOST FOCUS!") - focus = false - "" - } - + focus = false + "" } - fun gl() = html.webgl + } - fun resize() { - val canvas = gl().canvas + fun gl() = html.webgl - // Check if the canvas is not the same size. - val windowWidth = window.innerWidth.toInt() - val windowHeight = window.innerHeight.toInt() + fun resize() { + val canvas = gl().canvas - if (view.lastWindowWidth != windowWidth || - view.lastWindowHeight != windowHeight) { - view.lastWindowWidth = windowWidth - view.lastWindowHeight = windowHeight - view.windowWidth = windowWidth - view.windowHeight = windowHeight + // Check if the canvas is not the same size. + val windowWidth = window.innerWidth.toInt() + val windowHeight = window.innerHeight.toInt() - view.updateView() + if (view.lastWindowWidth != windowWidth || + view.lastWindowHeight != windowHeight) { + view.lastWindowWidth = windowWidth + view.lastWindowHeight = windowHeight + view.windowWidth = windowWidth + view.windowHeight = windowHeight - val textCanvas = html.canvas2d.canvas + view.updateView() - // Make the canvas the same size - canvas.width = view.width.toInt() - canvas.height = view.height.toInt() + val textCanvas = html.canvas2d.canvas - textCanvas.width = view.width.toInt() - textCanvas.height = view.height.toInt() + // Make the canvas the same size + canvas.width = view.width.toInt() + canvas.height = view.height.toInt() - gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) + textCanvas.width = view.width.toInt() + textCanvas.height = view.height.toInt() - borderLeft = (windowWidth - view.windowWidth) / 2 - borderTop = (windowHeight - view.windowHeight) / 2 + gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) - canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) - textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) + borderLeft = (windowWidth - view.windowWidth) / 2 + borderTop = (windowHeight - view.windowHeight) / 2 + + canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + } + } + + fun start(startScreen: Screen) { + if (started) { + throw IllegalStateException("You can only start a game once!") + } + + setScreen(startScreen) + + // start game loop + started = true + gameLoop() + } + + fun setScreen(screen: Screen) { + currentScreen.unloadResources() + + currentScreen = screen + + screen.loadResources() + } + + fun setClearColor(r: Float, g: Float, b: Float, a: Float) { + clearRed = r + clearGreen = g + clearBlue = b + clearAlpha = a + } + + fun gameLoop() { + try { + if (!Textures.ready()) { + gl().clearColor(1f, 1f, 1f, 1f) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } else { + resize() + + if (!pause) { + html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); + + if (clearScreenEveryFrame) { + gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } + + gl().enable(WebGLRenderingContext.BLEND) + gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); + + val time = Date().getTime() + currentDelta = ((time - currentTime) / 1000f).toFloat() + currentTime = time + + val timeInSeconds = (currentTime - start) / 1000f + + fpsCountTime += currentDelta + fpsCount++ + while (fpsCountTime > 1f) { + fps = fpsCount + fpsCountTime -= 1f + fpsCount = 0 + } + + if (focus) { + currentScreen.update(timeInSeconds.toFloat(), currentDelta) + } + + currentScreen.render() } + } + } catch (e: Exception) { + println("Some error...") + console.log(e) } - fun start(startScreen: Screen) { - if (started) { - throw IllegalStateException("You can only start a game once!") - } - - setScreen(startScreen) - - // start game loop - started = true - gameLoop() + window.requestAnimationFrame { + gameLoop() } - - fun setScreen(screen: Screen) { - currentScreen.unloadResources() - - currentScreen = screen - - screen.loadResources() - } - - fun setClearColor(r: Float, g: Float, b: Float, a: Float) { - clearRed = r - clearGreen = g - clearBlue = b - clearAlpha = a - } - - fun gameLoop() { - try { - if (!Textures.ready()) { - gl().clearColor(1f, 1f, 1f, 1f) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } else { - resize() - - if (!pause) { - html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); - - if (clearScreenEveryFrame) { - gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } - - gl().enable(WebGLRenderingContext.BLEND) - gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); - - val time = Date().getTime() - currentDelta = ((time - currentTime) / 1000f).toFloat() - currentTime = time - - val timeInSeconds = (currentTime - start) / 1000f - - fpsCountTime += currentDelta - fpsCount++ - while (fpsCountTime > 1f) { - fps = fpsCount - fpsCountTime -= 1f - fpsCount = 0 - } - - if (focus) { - currentScreen.update(timeInSeconds.toFloat(), currentDelta) - } - - currentScreen.render() - } - } - } catch(e: Exception) { - println("Some error...") - console.log(e) - } - - window.requestAnimationFrame { - gameLoop() - } - } + } } diff --git a/src/main/kotlin/games/perses/game/Screen.kt b/src/main/kotlin/games/perses/game/Screen.kt index 10b6eae..7b381e7 100644 --- a/src/main/kotlin/games/perses/game/Screen.kt +++ b/src/main/kotlin/games/perses/game/Screen.kt @@ -8,31 +8,31 @@ abstract class Screen { - open fun loadResources() {} + open fun loadResources() {} - @Deprecated( + @Deprecated( message = "replace with unloadResources", replaceWith = ReplaceWith("unloadResources()") - ) - open fun closeResources() { - unloadResources() - } + ) + open fun closeResources() { + unloadResources() + } - open fun unloadResources() {} + open fun unloadResources() {} - abstract fun update(time: Float, delta: Float) + abstract fun update(time: Float, delta: Float) - abstract fun render() + abstract fun render() } -class DefaultScreen: Screen() { - override fun update(time: Float, delta: Float) { - } +class DefaultScreen : Screen() { + override fun update(time: Float, delta: Float) { + } - override fun render() { - // show loading message? - Game.gl().clearColor(1f, 1f, 0f, 1f) - Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } + override fun render() { + // show loading message? + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } } diff --git a/src/main/kotlin/games/perses/game/View.kt b/src/main/kotlin/games/perses/game/View.kt index 540a44d..16c9913 100644 --- a/src/main/kotlin/games/perses/game/View.kt +++ b/src/main/kotlin/games/perses/game/View.kt @@ -4,39 +4,39 @@ import kotlin.browser.document enum class ViewType { - PROJECTION, - WIDTH, - HEIGHT, - ABSOLUTE + PROJECTION, + WIDTH, + HEIGHT, + ABSOLUTE } class View( - var lastWindowWidth: Int = 2000, - var lastWindowHeight: Int = 1000, - var windowWidth: Int = 2000, - var windowHeight: Int = 1000, - var width: Float = 1024f, - var height: Float = 1024f, - var angle: Float = 60f, - var near: Float = -0.1f, - var far: Float = -100f, - var minAspectRatio: Float = 1f, - var maxAspectRatio: Float = 1f, - var leftOffset: Int = 0, - var bottomOffset: Int = 0, - var viewType: ViewType = ViewType.WIDTH, - var drawMode: DrawMode = DrawMode.LINEAR) { - var vMatrix = Matrix4() - var aspectRatio = 1f + var lastWindowWidth: Int = 2000, + var lastWindowHeight: Int = 1000, + var windowWidth: Int = 2000, + var windowHeight: Int = 1000, + var width: Float = 1024f, + var height: Float = 1024f, + var angle: Float = 60f, + var near: Float = -0.1f, + var far: Float = -100f, + var minAspectRatio: Float = 1f, + var maxAspectRatio: Float = 1f, + var leftOffset: Int = 0, + var bottomOffset: Int = 0, + var viewType: ViewType = ViewType.WIDTH, + var drawMode: DrawMode = DrawMode.LINEAR) { + var vMatrix = Matrix4() + var aspectRatio = 1f - init { - updateView() - } + init { + updateView() + } - fun requestFullscreen() { - val element = document.body - //language=javascript - js(""" + fun requestFullscreen() { + val element = document.body + //language=javascript + js(""" if(element.requestFullscreen) { element.requestFullscreen(); } else if(element.mozRequestFullScreen) { @@ -47,10 +47,10 @@ element.msRequestFullscreen(); } """) - } + } - fun exitFullscreen() { - js(""" + fun exitFullscreen() { + js(""" if(document.exitFullscreen) { document.exitFullscreen(); } else if(document.mozCancelFullScreen) { @@ -59,178 +59,178 @@ document.webkitExitFullscreen(); } """) + } + + fun switchFullscreen() { + if (isFullscreen()) { + exitFullscreen() + } else { + requestFullscreen() + } + } + + fun isFullscreen(): Boolean { + val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + + return fse != undefined + } + + fun updateView() { + aspectRatio = windowWidth / windowHeight.toFloat() + + if (aspectRatio < minAspectRatio) { + aspectRatio = minAspectRatio + + windowHeight = (windowWidth / aspectRatio).toInt() } - fun switchFullscreen() { - if (isFullscreen()) { - exitFullscreen() - } else { - requestFullscreen() - } + if (aspectRatio > maxAspectRatio) { + aspectRatio = maxAspectRatio + + windowWidth = (windowHeight * aspectRatio).toInt() } - fun isFullscreen(): Boolean { - val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + when (viewType) { + ViewType.ABSOLUTE -> { + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.WIDTH -> { + height = width / aspectRatio - return fse != undefined + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.HEIGHT -> { + width = height * aspectRatio + + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.PROJECTION -> { + vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun updateView() { - aspectRatio = windowWidth / windowHeight.toFloat() + //println("width: $width, height: $height") + } - if (aspectRatio < minAspectRatio) { - aspectRatio = minAspectRatio + fun screenToGameCoordX(screenX: Float): Float { + var result = screenX - windowHeight = (windowWidth / aspectRatio).toInt() - } - - if (aspectRatio > maxAspectRatio) { - aspectRatio = maxAspectRatio - - windowWidth = (windowHeight * aspectRatio).toInt() - } - - when (viewType) { - ViewType.ABSOLUTE -> { - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.WIDTH -> { - height = width / aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.HEIGHT -> { - width = height * aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.PROJECTION -> { - vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } - - //println("width: $width, height: $height") + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = ((screenX - Game.borderLeft) * width / windowWidth) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordX(screenX: Float): Float { - var result = screenX + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( (screenX - Game.borderLeft) * width / windowWidth ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun screenToGameCoordY(screenY: Float): Float { + var result = screenY - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - ((screenY - Game.borderTop) * height / windowHeight) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordY(screenY: Float): Float { - var result = screenY + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( (screenY - Game.borderTop) * height / windowHeight ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordX(gameX: Float): Float { + var result = gameX + val normalizedX = gameX + (width / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = (gameX / width * windowWidth) + Game.borderLeft + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordX(gameX: Float): Float { - var result = gameX - val normalizedX = gameX + (width / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( gameX / width * windowWidth ) + Game.borderLeft - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordY(gameY: Float): Float { + var result = gameY + val normalizedY = gameY + (height / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - (gameY / height * windowHeight) + Game.borderTop + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordY(gameY: Float): Float { - var result = gameY - val normalizedY = gameY + (height / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( gameY / height * windowHeight ) + Game.borderTop - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun setToWidth(width: Float) { + this.width = width + this.viewType = ViewType.WIDTH - return result - } + updateView() + } - fun setToWidth(width: Float) { - this.width = width - this.viewType = ViewType.WIDTH + fun setToHeight(height: Float) { + this.height = height + this.viewType = ViewType.HEIGHT - updateView() - } + updateView() + } - fun setToHeight(height: Float) { - this.height = height - this.viewType = ViewType.HEIGHT + fun setProjection(angle: Float) { + this.angle = angle + this.viewType = ViewType.PROJECTION - updateView() - } + updateView() + } - fun setProjection(angle: Float) { - this.angle = angle - this.viewType = ViewType.PROJECTION + fun setNear(near: Float) { + this.near = near - updateView() - } + updateView() + } - fun setNear(near: Float) { - this.near = near + fun setFar(far: Float) { + this.far = far - updateView() - } - - fun setFar(far: Float) { - this.far = far - - updateView() - } + updateView() + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/input/Input.kt b/src/main/kotlin/games/perses/input/Input.kt index 71a3adc..58c4f23 100644 --- a/src/main/kotlin/games/perses/input/Input.kt +++ b/src/main/kotlin/games/perses/input/Input.kt @@ -15,235 +15,235 @@ */ enum class KeyCode(val keyCode: Int) { - BACKSPACE(8), - TAB(9), - ENTER(13), - SHIFT(16), - CTRL(17), - ALT(18), - PAUSE_BREAK(19), - CAPS_LOCK(20), - ESCAPE(27), - SPACE(32), - PAGE_UP(33), - PAGE_DOWN(34), - END(35), - HOME(36), - LEFT_ARROW(37), - UP_ARROW(38), - RIGHT_ARROW(39), - DOWN_ARROW(40), - INSERT(45), - DELETE(46), - NR_0(48), - NR_1(49), - NR_2(50), - NR_3(51), - NR_4(52), - NR_5(53), - NR_6(54), - NR_7(55), - NR_8(56), - NR_9(57), - A(65), - B(66), - C(67), - D(68), - E(69), - F(70), - G(71), - H(72), - I(73), - J(74), - K(75), - L(76), - M(77), - N(78), - O(79), - P(80), - Q(81), - R(82), - S(83), - T(84), - U(85), - V(86), - W(87), - X(88), - Y(89), - Z(90), - LEFT_WINDOW_KEY(91), - RIGHT_WINDOW_KEY(92), - SELECT_KEY(93), - NUMPAD_0(96), - NUMPAD_1(97), - NUMPAD_2(98), - NUMPAD_3(99), - NUMPAD_4(100), - NUMPAD_5(101), - NUMPAD_6(102), - NUMPAD_7(103), - NUMPAD_8(104), - NUMPAD_9(105), - MULTIPLY(106), - ADD(107), - SUBTRACT(109), - DECIMAL_POINT(110), - DIVIDE(111), - F1(112), - F2(113), - F3(114), - F4(115), - F5(116), - F6(117), - F7(118), - F8(119), - F9(120), - F10(121), - F11(122), - F12(123), - NUM_LOCK(144), - SCROLL_LOCK(145), - SEMI_COLON(186), - EQUAL_SIGN(187), - COMMA(188), - DASH(189), - PERIOD(190), - FORWARD_SLASH(191), - GRAVE_ACCENT(192), - OPEN_BRACKET(219), - BACK_SLASH(220), - CLOSE_BRAKET(221), - SINGLE_QUOTE(222), + BACKSPACE(8), + TAB(9), + ENTER(13), + SHIFT(16), + CTRL(17), + ALT(18), + PAUSE_BREAK(19), + CAPS_LOCK(20), + ESCAPE(27), + SPACE(32), + PAGE_UP(33), + PAGE_DOWN(34), + END(35), + HOME(36), + LEFT_ARROW(37), + UP_ARROW(38), + RIGHT_ARROW(39), + DOWN_ARROW(40), + INSERT(45), + DELETE(46), + NR_0(48), + NR_1(49), + NR_2(50), + NR_3(51), + NR_4(52), + NR_5(53), + NR_6(54), + NR_7(55), + NR_8(56), + NR_9(57), + A(65), + B(66), + C(67), + D(68), + E(69), + F(70), + G(71), + H(72), + I(73), + J(74), + K(75), + L(76), + M(77), + N(78), + O(79), + P(80), + Q(81), + R(82), + S(83), + T(84), + U(85), + V(86), + W(87), + X(88), + Y(89), + Z(90), + LEFT_WINDOW_KEY(91), + RIGHT_WINDOW_KEY(92), + SELECT_KEY(93), + NUMPAD_0(96), + NUMPAD_1(97), + NUMPAD_2(98), + NUMPAD_3(99), + NUMPAD_4(100), + NUMPAD_5(101), + NUMPAD_6(102), + NUMPAD_7(103), + NUMPAD_8(104), + NUMPAD_9(105), + MULTIPLY(106), + ADD(107), + SUBTRACT(109), + DECIMAL_POINT(110), + DIVIDE(111), + F1(112), + F2(113), + F3(114), + F4(115), + F5(116), + F6(117), + F7(118), + F8(119), + F9(120), + F10(121), + F11(122), + F12(123), + NUM_LOCK(144), + SCROLL_LOCK(145), + SEMI_COLON(186), + EQUAL_SIGN(187), + COMMA(188), + DASH(189), + PERIOD(190), + FORWARD_SLASH(191), + GRAVE_ACCENT(192), + OPEN_BRACKET(219), + BACK_SLASH(220), + CLOSE_BRAKET(221), + SINGLE_QUOTE(222), - ESC(27), - LEFT(37), - UP(38), - DOWN(40), - RIGHT(39), - MINUS(109), - PLUS(107), + ESC(27), + LEFT(37), + UP(38), + DOWN(40), + RIGHT(39), + MINUS(109), + PLUS(107), } interface InputProcessor { - fun keyPressed(charCode: Int) + fun keyPressed(charCode: Int) - fun keyDown(keyCode: Int) + fun keyDown(keyCode: Int) - fun keyUp(keyCode: Int) + fun keyUp(keyCode: Int) - fun pointerClick(pointer: Int, x: Float, y: Float) + fun pointerClick(pointer: Int, x: Float, y: Float) - fun mouseMove(x: Float, y: Float) + fun mouseMove(x: Float, y: Float) } open class EmptyInputProcessor : InputProcessor { - override fun pointerClick(pointer: Int, x: Float, y: Float) { } + override fun pointerClick(pointer: Int, x: Float, y: Float) {} - override fun keyDown(keyCode: Int) { } + override fun keyDown(keyCode: Int) {} - override fun keyPressed(charCode: Int) { } + override fun keyPressed(charCode: Int) {} - override fun keyUp(keyCode: Int) { } + override fun keyUp(keyCode: Int) {} - override fun mouseMove(x: Float, y: Float) { } + override fun mouseMove(x: Float, y: Float) {} } object Input { - private val keys: MutableMap = HashMap() - private var inputProcesser: InputProcessor = EmptyInputProcessor() + private val keys: MutableMap = HashMap() + private var inputProcesser: InputProcessor = EmptyInputProcessor() - init { - val body = document.body - if (body != null) { - body.onkeydown = { - keyDown(it) - } + init { + val body = document.body + if (body != null) { + body.onkeydown = { + keyDown(it) + } - body.onkeyup = { - keyUp(it) - } + body.onkeyup = { + keyUp(it) + } - body.onkeypress = { - keyPress(it) - } + body.onkeypress = { + keyPress(it) + } - body.onclick = { - mouseClick(it) - } + body.onclick = { + mouseClick(it) + } - body.onmousedown = { - mouseMove(it) - } + body.onmousedown = { + mouseMove(it) + } - body.onmouseup = { - mouseMove(it) - } + body.onmouseup = { + mouseMove(it) + } - body.onmousemove = { - mouseMove(it) - } - } else { - console.log("Can't register key events, document.body is null!?") - } + body.onmousemove = { + mouseMove(it) + } + } else { + console.log("Can't register key events, document.body is null!?") } + } - fun setInputProcessor(processor: InputProcessor) { - this.inputProcesser = processor + fun setInputProcessor(processor: InputProcessor) { + this.inputProcesser = processor + } + + private fun keyDown(key: Event) { + if (key is KeyboardEvent) { + keys.put(key.keyCode, Date().getTime()) + + inputProcesser.keyDown(key.keyCode) } + } - private fun keyDown(key: Event) { - if (key is KeyboardEvent) { - keys.put(key.keyCode, Date().getTime()) + private fun keyUp(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyUp(key.keyCode) - inputProcesser.keyDown(key.keyCode) - } + keys.remove(key.keyCode) } + } - private fun keyUp(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyUp(key.keyCode) - - keys.remove(key.keyCode) - } + private fun keyPress(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyPressed(key.charCode) } + } - private fun keyPress(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyPressed(key.charCode) - } + private fun mouseClick(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + + inputProcesser.pointerClick(event.button.toInt(), vx, vy) } + } - private fun mouseClick(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + private fun mouseMove(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) - inputProcesser.pointerClick(event.button.toInt(), vx, vy) - } + inputProcesser.mouseMove(vx, vy) } + } - private fun mouseMove(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + fun isDown(keyCode: Int) = keys.containsKey(keyCode) - inputProcesser.mouseMove(vx, vy) - } - } + fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - fun isDown(keyCode: Int) = keys.containsKey(keyCode) + fun wasPressed(keyCode: Int, delta: Double): Boolean { + val time = keys[keyCode] - fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - - fun wasPressed(keyCode: Int, delta: Double): Boolean { - val time = keys[keyCode] - - return (time != null && time > (Date().getTime() - delta)) - } + return (time != null && time > (Date().getTime() - delta)) + } } diff --git a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt index f1c7808..f3d4126 100644 --- a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt +++ b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt @@ -11,201 +11,201 @@ */ class MapData { - var version: Int = 1 - var properties: MutableMap = HashMap() - var layers: Array? = null - var tilesets: Array? = null + var version: Int = 1 + var properties: MutableMap = HashMap() + var layers: Array? = null + var tilesets: Array? = null - var height: Int = 0 - var width: Int = 0 + var height: Int = 0 + var width: Int = 0 - var nextobjectid: Int = 0 - var orientation: String = "orthogonal" - var renderorder: String = "right-down" - var tileheight: Int = 0 - var tilewidth: Int = 0 + var nextobjectid: Int = 0 + var orientation: String = "orthogonal" + var renderorder: String = "right-down" + var tileheight: Int = 0 + var tilewidth: Int = 0 } class MapLayer { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var data: Array? = null - var encoding: String = "" - var x: Int = 0 - var y: Int = 0 - var width: Int = 0 - var height: Int = 0 - var name: String = "" - var opacity: Float = 1f - var type: String = "" - var visible: Boolean = true - var draworder: String = "" + var data: Array? = null + var encoding: String = "" + var x: Int = 0 + var y: Int = 0 + var width: Int = 0 + var height: Int = 0 + var name: String = "" + var opacity: Float = 1f + var type: String = "" + var visible: Boolean = true + var draworder: String = "" } class MapTileset { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var firstgid: Int = 0 - var image: String = "" - var imageheight: Int = 0 - var imagewidth: Int = 0 - var margin: Int = 0 - var name: String = "" - var spacing: Int = 0 - var tilecount: Int = 0 - var tileheight: Int = 0 - var tilewidth: Int = 0 - var tileproperties: MutableMap> = HashMap() + var firstgid: Int = 0 + var image: String = "" + var imageheight: Int = 0 + var imagewidth: Int = 0 + var margin: Int = 0 + var name: String = "" + var spacing: Int = 0 + var tilecount: Int = 0 + var tileheight: Int = 0 + var tilewidth: Int = 0 + var tileproperties: MutableMap> = HashMap() } class TilesetIndex( - val texture: Texture?, - val tcLeft: Float, - val tcTop: Float, - val tcRight: Float, - val tcBottom: Float, - val scale: Float - ) { - constructor() : this(null, 0f, 0f, 0f, 0f, 0f) + val texture: Texture?, + val tcLeft: Float, + val tcTop: Float, + val tcRight: Float, + val tcBottom: Float, + val scale: Float +) { + constructor() : this(null, 0f, 0f, 0f, 0f, 0f) - fun render(x: Float, y: Float) { - texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) - } + fun render(x: Float, y: Float) { + texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) + } } class TiledMap(dir: String = "", url: String) { - val properties: Map = HashMap() - val data: MapData - val tileset: Array - val tiles: Array - var first = true - //var tilesetIndex: Array = Array(0, { TilesetIndex() }) + val properties: Map = HashMap() + val data: MapData + val tileset: Array + val tiles: Array + var first = true + //var tilesetIndex: Array = Array(0, { TilesetIndex() }) - init { - var tileDir = dir - if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { - tileDir = tileDir + "/" - } - - data = JSON.parse(getUrlAsString(tileDir + url)) - //println("map data is loaded") - val tilesets = data.tilesets - if (tilesets != null) { - tileset = Array(tilesets.size, { "" }) - var maxGid = 0 - for (index in 0..tilesets.size - 1) { - tileset[index] = tilesets[index].name - Textures.load(tilesets[index].name, tileDir + tilesets[index].image) - maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) - } - - tiles = Array(maxGid, { TilesetIndex() }) - } else { - tileset = Array(0, { "" }) - tiles = Array(0, { TilesetIndex() }) - } - - cacheTiles() + init { + var tileDir = dir + if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { + tileDir = tileDir + "/" } - fun cacheTiles() { - if (!Textures.ready()) { - window.setTimeout({ cacheTiles() }, 10) - } else { - val tilesets = data.tilesets - var tcLeft = 0f - var tcTop = 0f - var tcRight = 0f - var tcBottom = 0f + data = JSON.parse(getUrlAsString(tileDir + url)) + //println("map data is loaded") + val tilesets = data.tilesets + if (tilesets != null) { + tileset = Array(tilesets.size, { "" }) + var maxGid = 0 + for (index in 0..tilesets.size - 1) { + tileset[index] = tilesets[index].name + Textures.load(tilesets[index].name, tileDir + tilesets[index].image) + maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) + } - if (tilesets != null) { - - - for (tileset in tilesets) { - val tilesHor = tileset.imagewidth / tileset.tilewidth - val tilesVer = tileset.imageheight / tileset.tileheight - val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) - - for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { - val texture = Textures.get(tileset.name) - - val gid = index - tileset.firstgid - - val xi = gid % tilesHor - var yi = gid / tilesHor - yi = tilesVer - yi - 1 - val tw = 1f / tilesHor.toFloat() - val th = 1f / tilesVer.toFloat() - - val pixelW = 0.1f / tileset.tilewidth - val pixelH = 0.1f / tileset.tileheight - - tcLeft = xi * tw - tcRight = tcLeft + tw - - // switch up/down because of texture coord 0,0 in left bottom corner - tcBottom = yi * th - tcTop = tcBottom + th - - tcLeft += pixelW - tcRight -= pixelW - - tcBottom += pixelH - tcTop -= pixelH - - tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) - } - } - } - } + tiles = Array(maxGid, { TilesetIndex() }) + } else { + tileset = Array(0, { "" }) + tiles = Array(0, { TilesetIndex() }) } - fun drawTile(tile: Int, x: Float, y: Float) { - tiles[tile].render(x, y) + cacheTiles() + } + + fun cacheTiles() { + if (!Textures.ready()) { + window.setTimeout({ cacheTiles() }, 10) + } else { + val tilesets = data.tilesets + var tcLeft = 0f + var tcTop = 0f + var tcRight = 0f + var tcBottom = 0f + + if (tilesets != null) { + + + for (tileset in tilesets) { + val tilesHor = tileset.imagewidth / tileset.tilewidth + val tilesVer = tileset.imageheight / tileset.tileheight + val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) + + for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { + val texture = Textures.get(tileset.name) + + val gid = index - tileset.firstgid + + val xi = gid % tilesHor + var yi = gid / tilesHor + yi = tilesVer - yi - 1 + val tw = 1f / tilesHor.toFloat() + val th = 1f / tilesVer.toFloat() + + val pixelW = 0.1f / tileset.tilewidth + val pixelH = 0.1f / tileset.tileheight + + tcLeft = xi * tw + tcRight = tcLeft + tw + + // switch up/down because of texture coord 0,0 in left bottom corner + tcBottom = yi * th + tcTop = tcBottom + th + + tcLeft += pixelW + tcRight -= pixelW + + tcBottom += pixelH + tcTop -= pixelH + + tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) + } + } + } + } + } + + fun drawTile(tile: Int, x: Float, y: Float) { + tiles[tile].render(x, y) + } + + fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { + var x = 0f + var y = 0f + val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") + val layer = layers[layerIndex] + + val layerData = layer.data + if (layerData != null) { + for (index in layerData.indices) { + // todo: determine if in view + // todo: determine tilewidth + //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { + drawTile(layerData[index], xo + x * 128f, yo + y * 128f) + + when (data.renderorder) { + "right-down" -> { + x++ + if (x >= layer.width) { + x = 0f + y-- + } + } + else -> { + throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") + } + } + //} + } } - fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { - var x = 0f - var y = 0f - val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") - val layer = layers[layerIndex] + val tilesets = data.tilesets + if (tilesets != null) { + for (tileset in tilesets) { + if (Textures.has(tileset.name)) { + val tx = Textures.get(tileset.name) - val layerData = layer.data - if (layerData != null) { - for (index in layerData.indices) { - // todo: determine if in view - // todo: determine tilewidth - //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { - drawTile(layerData[index], xo + x * 128f, yo + y * 128f) - - when (data.renderorder) { - "right-down" -> { - x++ - if (x >= layer.width) { - x = 0f - y-- - } - } - else -> { - throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") - } - } - //} - } + tx.render() } - - val tilesets = data.tilesets - if (tilesets != null) { - for (tileset in tilesets) { - if (Textures.has(tileset.name)) { - val tx = Textures.get(tileset.name) - - tx.render() - } - } - } - - - first = false + } } + + + first = false + } } diff --git a/src/main/kotlin/games/perses/math/Matrix4.kt b/src/main/kotlin/games/perses/math/Matrix4.kt index 7da03cd..bd274bf 100644 --- a/src/main/kotlin/games/perses/math/Matrix4.kt +++ b/src/main/kotlin/games/perses/math/Matrix4.kt @@ -10,184 +10,184 @@ */ class Matrix4 { - internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - internal var temp = FloatArray(16) + internal var temp = FloatArray(16) - private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - fun get(): FloatArray { - return matrix + fun get(): FloatArray { + return matrix + } + + fun getFloat32Array() = Float32Array(get().toTypedArray()) + + fun set(values: FloatArray) { + if (values.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun getFloat32Array() = Float32Array(get().toTypedArray()) + matrix = values + } - fun set(values: FloatArray) { - if (values.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } + fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { + val r = (angle / 180f * Math.PI).toFloat() + val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() - matrix = values + matrix[0] = f / imageAspectRatio + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + + matrix[4] = 0.0f + matrix[5] = f + matrix[6] = 0.0f + matrix[7] = 0.0f + + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = -(far + near) / (far - near) + matrix[11] = -1.0f + + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = -(2.0f * far * near) / (far - near) + matrix[15] = 0.0f + } + + fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { + matrix[0] = 2f / (right - left) + matrix[1] = 0f + matrix[2] = 0f + matrix[3] = 0f + + matrix[4] = 0f + matrix[5] = 2f / (top - bottom) + matrix[6] = 0f + matrix[7] = 0f + + matrix[8] = 0f + matrix[9] = 0f + matrix[10] = -2f / (far - near) + matrix[11] = 0f + + matrix[12] = -(right + left) / (right - left) + matrix[13] = -(top + bottom) / (top - bottom) + matrix[14] = -(far + near) / (far - near) + matrix[15] = 1f + } + + fun setToIdentity() { + matrix[0] = 1.0f + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + matrix[4] = 0.0f + matrix[5] = 1.0f + matrix[6] = 0.0f + matrix[7] = 0.0f + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = 1.0f + matrix[11] = 0.0f + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = 0.0f + matrix[15] = 1.0f + } + + fun mul(other: Matrix4) { + mul(other.get()) + } + + protected fun mul(other: FloatArray) { + if (other.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { - val r = (angle / 180f * Math.PI).toFloat() - val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() + temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] + temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] + temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] + temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] + temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] + temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] + temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] + temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] + temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] + temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] + temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] + temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] + temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] + temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] + temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] + temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - matrix[0] = f / imageAspectRatio - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f + matrix[0] = temp[0] + matrix[1] = temp[1] + matrix[2] = temp[2] + matrix[3] = temp[3] + matrix[4] = temp[4] + matrix[5] = temp[5] + matrix[6] = temp[6] + matrix[7] = temp[7] + matrix[8] = temp[8] + matrix[9] = temp[9] + matrix[10] = temp[10] + matrix[11] = temp[11] + matrix[12] = temp[12] + matrix[13] = temp[13] + matrix[14] = temp[14] + matrix[15] = temp[15] + } - matrix[4] = 0.0f - matrix[5] = f - matrix[6] = 0.0f - matrix[7] = 0.0f + fun translate(x: Float, y: Float, z: Float) { + translateMatrix[12] = x + translateMatrix[13] = y + translateMatrix[14] = z - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = -(far + near) / (far - near) - matrix[11] = -1.0f + mul(translateMatrix) + } - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = -(2.0f * far * near) / (far - near) - matrix[15] = 0.0f - } + fun scale(x: Float, y: Float, z: Float) { + scaleMatrix[0] = x + scaleMatrix[5] = y + scaleMatrix[10] = z - fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { - matrix[0] = 2f / (right - left) - matrix[1] = 0f - matrix[2] = 0f - matrix[3] = 0f + mul(scaleMatrix) + } - matrix[4] = 0f - matrix[5] = 2f / (top - bottom) - matrix[6] = 0f - matrix[7] = 0f + fun rotateX(angle: Float) { + rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() + rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() + rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() + rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - matrix[8] = 0f - matrix[9] = 0f - matrix[10] = -2f / (far - near) - matrix[11] = 0f + mul(rotateXMatrix) + } - matrix[12] = - (right + left) / (right - left) - matrix[13] = - (top + bottom) / (top - bottom) - matrix[14] = - (far + near) / (far - near) - matrix[15] = 1f - } + fun rotateY(angle: Float) { + rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() + rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() + rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - fun setToIdentity() { - matrix[0] = 1.0f - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f - matrix[4] = 0.0f - matrix[5] = 1.0f - matrix[6] = 0.0f - matrix[7] = 0.0f - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = 1.0f - matrix[11] = 0.0f - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = 0.0f - matrix[15] = 1.0f - } + mul(rotateYMatrix) + } - fun mul(other: Matrix4) { - mul(other.get()) - } + fun rotateZ(angle: Float) { + rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() + rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() + rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - protected fun mul(other: FloatArray) { - if (other.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } - - temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] - temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] - temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] - temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] - temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] - temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] - temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] - temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] - temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] - temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] - temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] - temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] - temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] - temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] - temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] - temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - - matrix[0] = temp[0] - matrix[1] = temp[1] - matrix[2] = temp[2] - matrix[3] = temp[3] - matrix[4] = temp[4] - matrix[5] = temp[5] - matrix[6] = temp[6] - matrix[7] = temp[7] - matrix[8] = temp[8] - matrix[9] = temp[9] - matrix[10] = temp[10] - matrix[11] = temp[11] - matrix[12] = temp[12] - matrix[13] = temp[13] - matrix[14] = temp[14] - matrix[15] = temp[15] - } - - fun translate(x: Float, y: Float, z: Float) { - translateMatrix[12] = x - translateMatrix[13] = y - translateMatrix[14] = z - - mul(translateMatrix) - } - - fun scale(x: Float, y: Float, z: Float) { - scaleMatrix[0] = x - scaleMatrix[5] = y - scaleMatrix[10] = z - - mul(scaleMatrix) - } - - fun rotateX(angle: Float) { - rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() - rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() - rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() - rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateXMatrix) - } - - fun rotateY(angle: Float) { - rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() - rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() - rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateYMatrix) - } - - fun rotateZ(angle: Float) { - rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() - rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() - rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateZMatrix) - } + mul(rotateZMatrix) + } } diff --git a/src/main/kotlin/games/perses/net/NetUtils.kt b/src/main/kotlin/games/perses/net/NetUtils.kt index 5b5b820..148b920 100644 --- a/src/main/kotlin/games/perses/net/NetUtils.kt +++ b/src/main/kotlin/games/perses/net/NetUtils.kt @@ -9,10 +9,10 @@ */ fun getUrlAsString(url: String): String { - val req = XMLHttpRequest() + val req = XMLHttpRequest() - req.open("GET", url, false) - req.send(null) + req.open("GET", url, false) + req.send(null) - return req.responseText + return req.responseText } diff --git a/src/main/kotlin/games/perses/shader/ShaderProgram.kt b/src/main/kotlin/games/perses/shader/ShaderProgram.kt index cf07c0f..7dde03a 100644 --- a/src/main/kotlin/games/perses/shader/ShaderProgram.kt +++ b/src/main/kotlin/games/perses/shader/ShaderProgram.kt @@ -1,6 +1,10 @@ package games.perses.shader -import org.khronos.webgl.* +import org.khronos.webgl.Float32Array +import org.khronos.webgl.WebGLBuffer +import org.khronos.webgl.WebGLProgram +import org.khronos.webgl.WebGLRenderingContext +import org.khronos.webgl.WebGLShader /** * User: rnentjes @@ -9,103 +13,125 @@ */ class ShaderProgram( - val webgl: WebGLRenderingContext, - val drawType: Int, - vertexShaderSource: String, - fragmentShaderSource: String, - val vainfo: Array, - val setter: (program: ShaderProgram, data: T) -> Unit) { + val webgl: WebGLRenderingContext, + val drawType: Int, + vertexShaderSource: String, + fragmentShaderSource: String, + val vainfo: Array, + val setter: (program: ShaderProgram, data: T) -> Unit +) { - var shaderProgram: WebGLProgram - var vertex: WebGLShader - var fragment: WebGLShader + var shaderProgram: WebGLProgram + var vertex: WebGLShader + var fragment: WebGLShader - var verticesBlockSize = 0 - var drawLength = 0 + var verticesBlockSize = 0 + var drawLength = 0 - init { - vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER) - fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER) + init { + vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER) + fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER) - shaderProgram = webgl.createProgram() ?: throw IllegalStateException("Unable to request shader program from webgl context!") - webgl.attachShader(shaderProgram, vertex) - webgl.attachShader(shaderProgram, fragment) - webgl.linkProgram(shaderProgram) + shaderProgram = webgl.createProgram() ?: throw IllegalStateException( + "Unable to request shader program from webgl context!" + ) + webgl.attachShader(shaderProgram, vertex) + webgl.attachShader(shaderProgram, fragment) + webgl.linkProgram(shaderProgram) - if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) { - //println(webgl.getProgramInfoLog(shaderProgram)) - throw IllegalStateException("Unable to compile shader program!") - } - - webgl.useProgram(shaderProgram) - - this.verticesBlockSize = 0 - - // set attribute locations... - for (info in vainfo.iterator()) { - info.location = webgl.getAttribLocation(shaderProgram, info.locationName) - info.offset = verticesBlockSize - - verticesBlockSize += info.numElements - //println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}") - } - - when(drawType) { - WebGLRenderingContext.TRIANGLES -> { - drawLength = verticesBlockSize * 3 - } - else -> { - drawLength = verticesBlockSize - } - } - - //println("verticesBlockSize $verticesBlockSize") - - //println("ShaderProgram constructor done") + if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) { + //println(webgl.getProgramInfoLog(shaderProgram)) + throw IllegalStateException("Unable to compile shader program!") } - private fun compileShader(source: String, type: Int): WebGLShader { - val result: WebGLShader = webgl.createShader(type) ?: throw IllegalStateException("Unable to request shader from webgl context!") + webgl.useProgram(shaderProgram) - webgl.shaderSource(result, source) - webgl.compileShader(result) + this.verticesBlockSize = 0 - if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) { - throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}") - } + // set attribute locations... + for (info in vainfo.iterator()) { + info.location = webgl.getAttribLocation(shaderProgram, info.locationName) + info.offset = verticesBlockSize - return result + verticesBlockSize += info.numElements + //println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}") } - fun begin(attribBuffer: WebGLBuffer, userdata: T) { - webgl.useProgram(shaderProgram); - webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); - - // set attribute locations... - for (info in vainfo.iterator()) { - webgl.enableVertexAttribArray(info.location) - webgl.vertexAttribPointer(info.location, info.numElements, WebGLRenderingContext.FLOAT, false, verticesBlockSize * 4, info.offset * 4) - } - - setter(this, userdata) + when (drawType) { + WebGLRenderingContext.TRIANGLES -> { + drawLength = verticesBlockSize * 3 + } + else -> { + drawLength = verticesBlockSize + } } - fun end() { - for (info in vainfo.iterator()) { - webgl.disableVertexAttribArray(info.location); - } - webgl.useProgram(null) + //println("verticesBlockSize $verticesBlockSize") + + //println("ShaderProgram constructor done") + } + + private fun compileShader(source: String, type: Int): WebGLShader { + val result: WebGLShader = webgl.createShader(type) + ?: throw IllegalStateException("Unable to request shader from webgl context!") + + webgl.shaderSource(result, source) + webgl.compileShader(result) + + if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) { + throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}") } - fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location); + return result + } - fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location); + fun begin(attribBuffer: WebGLBuffer, userdata: T) { + webgl.useProgram(shaderProgram); + webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); - fun setUniform1f(location: String, value: Float) { webgl.uniform1f(getUniformLocation(location), value); } - fun setUniform2f(location: String, v1: Float, v2: Float) { webgl.uniform2f(getUniformLocation(location), v1, v2); } - fun setUniform3f(location: String, v1: Float, v2: Float, v3: Float) { webgl.uniform3f(getUniformLocation(location), v1, v2, v3); } - fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); } - fun setUniform1i(location: String, value: Int) { webgl.uniform1i(getUniformLocation(location), value); } - fun setUniformMatrix4fv(location: String, value: Float32Array) { webgl.uniformMatrix4fv(getUniformLocation(location), false, value); } + // set attribute locations... + for (info in vainfo.iterator()) { + webgl.enableVertexAttribArray(info.location) + webgl.vertexAttribPointer( + info.location, + info.numElements, + WebGLRenderingContext.FLOAT, + false, + verticesBlockSize * 4, + info.offset * 4 + ) + } + + setter(this, userdata) + } + + fun end() { + for (info in vainfo.iterator()) { + webgl.disableVertexAttribArray(info.location); + } + webgl.useProgram(null) + } + + fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location); + + fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location); + + fun setUniform1f(location: String, value: Float) { + webgl.uniform1f(getUniformLocation(location), value); } + + fun setUniform2f(location: String, v1: Float, v2: Float) { + webgl.uniform2f(getUniformLocation(location), v1, v2); } + + fun setUniform3f(location: String, v1: Float, v2: Float, v3: Float) { + webgl.uniform3f(getUniformLocation(location), v1, v2, v3); } + + fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { + webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); } + + fun setUniform1i(location: String, value: Int) { + webgl.uniform1i(getUniformLocation(location), value); } + + fun setUniformMatrix4fv(location: String, value: Float32Array) { + webgl.uniformMatrix4fv(getUniformLocation(location), false, value); } } diff --git a/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt b/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt index d9a3908..d65cf7f 100644 --- a/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt +++ b/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt @@ -11,64 +11,67 @@ * Time: 11:57 */ -class VertextAttributeInfo(val locationName: String, val numElements: Int) { - var location = 0 - var offset = 0 +class VertextAttributeInfo( + val locationName: String, + val numElements: Int +) { + var location = 0 + var offset = 0 } class ShaderProgramMesh( - val shaderProgram: ShaderProgram + val shaderProgram: ShaderProgram ) { - val webgl = shaderProgram.webgl - val data: Float32Array = Float32Array(20000 - (20000 % shaderProgram.drawLength)) - var currentIndex: Int = 0 - val attribBuffer: WebGLBuffer - var counter = 0 + val webgl = shaderProgram.webgl + val data: Float32Array = Float32Array(20000 - (20000 % shaderProgram.drawLength)) + var currentIndex: Int = 0 + val attribBuffer: WebGLBuffer + var counter = 0 - init { - attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!") - webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer) + init { + attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!") + webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer) + } + + fun queue(vararg vertices: Float) { + for (vertice in vertices) { + data[currentIndex++] = vertice } - fun queue(vararg vertices: Float) { - for (vertice in vertices) { - data[currentIndex++] = vertice - } - - if (bufferFull()) { - println("Skipped draw call, to many values!") - currentIndex = 0 - } + if (bufferFull()) { + println("Skipped draw call, to many values!") + currentIndex = 0 } + } - fun queueArray(vertices: Array) { - data.set(vertices, currentIndex) - currentIndex += vertices.size + fun queueArray(vertices: Array) { + data.set(vertices, currentIndex) + currentIndex += vertices.size - if (bufferFull()) { - println("Skipped draw call, to many values!") - currentIndex = 0 - } + if (bufferFull()) { + println("Skipped draw call, to many values!") + currentIndex = 0 } + } - fun remaining() = data.length - currentIndex + fun remaining() = data.length - currentIndex - fun bufferFull() = currentIndex == data.length + fun bufferFull() = currentIndex == data.length - fun render(userdata: T) { - counter++ - if (currentIndex > 0) { - if (currentIndex % shaderProgram.verticesBlockSize != 0) { - throw IllegalStateException("Number of vertices not a multiple of the attribute block size!") - } + fun render(userdata: T) { + counter++ + if (currentIndex > 0) { + if (currentIndex % shaderProgram.verticesBlockSize != 0) { + throw IllegalStateException("Number of vertices not a multiple of the attribute block size!") + } - shaderProgram.begin(attribBuffer, userdata) + shaderProgram.begin(attribBuffer, userdata) - webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW) - webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize)) - currentIndex = 0 + webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW) + webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize)) + currentIndex = 0 - shaderProgram.end() - } + shaderProgram.end() } + } } diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml index 43edcc2..7ed1494 100644 --- a/.idea/modules/kudens_test.iml +++ b/.idea/modules/kudens_test.iml @@ -1,8 +1,9 @@ - + + $MODULE_DIR$/../../build/kotlinjs/kudens.js \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7ae9969..e7225a0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'perses.games' -version '1.1.6-SNAPSHOT' +version '1.1.7-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'idea' @@ -20,7 +20,7 @@ } buildscript { - ext.kotlin_version = '1.2.21' + ext.kotlin_version = '1.2.30' repositories { maven { url "http://nexus.astraeus.nl/nexus/content/groups/public" diff --git a/src/main/kotlin/games/perses/color/Color.kt b/src/main/kotlin/games/perses/color/Color.kt index 7f235b0..31b540f 100644 --- a/src/main/kotlin/games/perses/color/Color.kt +++ b/src/main/kotlin/games/perses/color/Color.kt @@ -10,107 +10,107 @@ object Color { - /** - * Converts an HSL color value to RGB. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes h, s, and l are contained in the set [0, 1] and - * returns r, g, and b in the set [0, 255]. + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. - * @param h The hue - * * - * @param s The saturation - * * - * @param l The lightness - * * - * @return int array, the RGB representation - */ - fun hslToRgb(h: Float, s: Float, l: Float): IntArray { - val r: Float - val g: Float - val b: Float + * @param h The hue + * * + * @param s The saturation + * * + * @param l The lightness + * * + * @return int array, the RGB representation + */ + fun hslToRgb(h: Float, s: Float, l: Float): IntArray { + val r: Float + val g: Float + val b: Float - if (s == 0f) { - b = l - g = b - r = g // achromatic - } else { - val q = if (l < 0.5f) l * (1 + s) else l + s - l * s - val p = 2 * l - q - r = hueToRgb(p, q, h + 1f / 3f) - g = hueToRgb(p, q, h) - b = hueToRgb(p, q, h - 1f / 3f) - } - val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) + if (s == 0f) { + b = l + g = b + r = g // achromatic + } else { + val q = if (l < 0.5f) l * (1 + s) else l + s - l * s + val p = 2 * l - q + r = hueToRgb(p, q, h + 1f / 3f) + g = hueToRgb(p, q, h) + b = hueToRgb(p, q, h - 1f / 3f) + } + val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) - return rgb + return rgb + } + + /** Helper method that converts hue to rgb */ + fun hueToRgb(p: Float, q: Float, t: Float): Float { + var lt = t + if (lt < 0f) { + lt += 1f + } + if (lt > 1f) { + lt -= 1f + } + if (lt < 1f / 6f) { + return p + (q - p) * 6f * lt + } + if (lt < 1f / 2f) { + return q + } + if (lt < 2f / 3f) { + return p + (q - p) * (2f / 3f - lt) * 6f + } + return p + } + + /** + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes pR, pG, and bpBare contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + + * @param pR The red color value + * * + * @param pG The green color value + * * + * @param pB The blue color value + * * + * @return float array, the HSL representation + */ + fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { + val r = pR / 255f + val g = pG / 255f + val b = pB / 255f + + val max = if (r > g && r > b) r else if (g > b) g else b + val min = if (r < g && r < b) r else if (g < b) g else b + + var h: Float + val s: Float + val l: Float + l = (max + min) / 2.0f + + if (max == min) { + s = 0.0f + h = s + } else { + val d = max - min + s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) + + if (r > g && r > b) + h = (g - b) / d + (if (g < b) 6.0f else 0.0f) + else if (g > b) + h = (b - r) / d + 2.0f + else + h = (r - g) / d + 4.0f + + h /= 6.0f } - /** Helper method that converts hue to rgb */ - fun hueToRgb(p: Float, q: Float, t: Float): Float { - var lt = t - if (lt < 0f) { - lt += 1f - } - if (lt > 1f) { - lt -= 1f - } - if (lt < 1f / 6f) { - return p + (q - p) * 6f * lt - } - if (lt < 1f / 2f) { - return q - } - if (lt < 2f / 3f) { - return p + (q - p) * (2f / 3f - lt) * 6f - } - return p - } - - /** - * Converts an RGB color value to HSL. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes pR, pG, and bpBare contained in the set [0, 255] and - * returns h, s, and l in the set [0, 1]. - - * @param pR The red color value - * * - * @param pG The green color value - * * - * @param pB The blue color value - * * - * @return float array, the HSL representation - */ - fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { - val r = pR / 255f - val g = pG / 255f - val b = pB / 255f - - val max = if (r > g && r > b) r else if (g > b) g else b - val min = if (r < g && r < b) r else if (g < b) g else b - - var h: Float - val s: Float - val l: Float - l = (max + min) / 2.0f - - if (max == min) { - s = 0.0f - h = s - } else { - val d = max - min - s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) - - if (r > g && r > b) - h = (g - b) / d + (if (g < b) 6.0f else 0.0f) - else if (g > b) - h = (b - r) / d + 2.0f - else - h = (r - g) / d + 4.0f - - h /= 6.0f - } - - val hsl = floatArrayOf(h, s, l) - return hsl - } + val hsl = floatArrayOf(h, s, l) + return hsl + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/game/Game.kt b/src/main/kotlin/games/perses/game/Game.kt index 0961316..1becee5 100644 --- a/src/main/kotlin/games/perses/game/Game.kt +++ b/src/main/kotlin/games/perses/game/Game.kt @@ -14,210 +14,210 @@ */ enum class DrawMode { - LINEAR, - NEAREST + LINEAR, + NEAREST } class HTMLElements { - var container: HTMLElement - var webgl: WebGLRenderingContext - var canvas2d: CanvasRenderingContext2D + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D - init { - container = document.createElement("div") as HTMLElement + init { + container = document.createElement("div") as HTMLElement - val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement - val canvas = document.createElement("canvas") as HTMLCanvasElement + val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + val canvas = document.createElement("canvas") as HTMLCanvasElement - container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") - webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" ) - canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" ) + container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;") - document.body!!.appendChild(container) - container.appendChild(webGlCanvas) - container.appendChild(canvas) + document.body!!.appendChild(container) + container.appendChild(webGlCanvas) + container.appendChild(canvas) - val canvas2dcanvas = canvas.getContext("2d") + val canvas2dcanvas = canvas.getContext("2d") - var webglcanvas = webGlCanvas.getContext("webgl") - if (webglcanvas == null) { - console.log("webgl context not found, trying experimental-webgl.") - webglcanvas = webGlCanvas.getContext("experimental-webgl") - } - - if (webglcanvas != null) { - webgl = webglcanvas as WebGLRenderingContext - } else { - console.log("webgl?", webglcanvas) - window.alert("Your browser doesn't seem to support webgl!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } - - if (canvas2dcanvas != null) { - canvas2d = canvas2dcanvas as CanvasRenderingContext2D - } else { - console.log("canvas2d?", canvas2dcanvas) - window.alert("Your browser doesn't seem to support 2d canvas!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } + var webglcanvas = webGlCanvas.getContext("webgl") + if (webglcanvas == null) { + console.log("webgl context not found, trying experimental-webgl.") + webglcanvas = webGlCanvas.getContext("experimental-webgl") } + + if (webglcanvas != null) { + webgl = webglcanvas as WebGLRenderingContext + } else { + console.log("webgl?", webglcanvas) + window.alert("Your browser doesn't seem to support webgl!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + + if (canvas2dcanvas != null) { + canvas2d = canvas2dcanvas as CanvasRenderingContext2D + } else { + console.log("canvas2d?", canvas2dcanvas) + window.alert("Your browser doesn't seem to support 2d canvas!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + } } object Game { - var started = false - val view: View = View() - val html: HTMLElements by lazy { HTMLElements() } - var currentScreen: Screen = DefaultScreen() - var start = Date().getTime() - var currentTime = start - var currentDelta = 0f - var pause: Boolean = false - var clearScreenEveryFrame = true + var started = false + val view: View = View() + val html: HTMLElements by lazy { HTMLElements() } + var currentScreen: Screen = DefaultScreen() + var start = Date().getTime() + var currentTime = start + var currentDelta = 0f + var pause: Boolean = false + var clearScreenEveryFrame = true - var clearRed = 0f - var clearGreen = 0f - var clearBlue = 0f - var clearAlpha = 1f + var clearRed = 0f + var clearGreen = 0f + var clearBlue = 0f + var clearAlpha = 1f - var fps = 0 - var fpsCount = 0 - var fpsCountTime = 0f + var fps = 0 + var fpsCount = 0 + var fpsCountTime = 0f - var borderLeft = 0 - var borderTop = 0 + var borderLeft = 0 + var borderTop = 0 - var focus = true + var focus = true - init { - window.onfocus = { - //println("GOT FOCUS!") + init { + window.onfocus = { + //println("GOT FOCUS!") - focus = true - "" - } - window.onblur = { - //println("LOST FOCUS!") + focus = true + "" + } + window.onblur = { + //println("LOST FOCUS!") - focus = false - "" - } - + focus = false + "" } - fun gl() = html.webgl + } - fun resize() { - val canvas = gl().canvas + fun gl() = html.webgl - // Check if the canvas is not the same size. - val windowWidth = window.innerWidth.toInt() - val windowHeight = window.innerHeight.toInt() + fun resize() { + val canvas = gl().canvas - if (view.lastWindowWidth != windowWidth || - view.lastWindowHeight != windowHeight) { - view.lastWindowWidth = windowWidth - view.lastWindowHeight = windowHeight - view.windowWidth = windowWidth - view.windowHeight = windowHeight + // Check if the canvas is not the same size. + val windowWidth = window.innerWidth.toInt() + val windowHeight = window.innerHeight.toInt() - view.updateView() + if (view.lastWindowWidth != windowWidth || + view.lastWindowHeight != windowHeight) { + view.lastWindowWidth = windowWidth + view.lastWindowHeight = windowHeight + view.windowWidth = windowWidth + view.windowHeight = windowHeight - val textCanvas = html.canvas2d.canvas + view.updateView() - // Make the canvas the same size - canvas.width = view.width.toInt() - canvas.height = view.height.toInt() + val textCanvas = html.canvas2d.canvas - textCanvas.width = view.width.toInt() - textCanvas.height = view.height.toInt() + // Make the canvas the same size + canvas.width = view.width.toInt() + canvas.height = view.height.toInt() - gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) + textCanvas.width = view.width.toInt() + textCanvas.height = view.height.toInt() - borderLeft = (windowWidth - view.windowWidth) / 2 - borderTop = (windowHeight - view.windowHeight) / 2 + gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) - canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) - textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) + borderLeft = (windowWidth - view.windowWidth) / 2 + borderTop = (windowHeight - view.windowHeight) / 2 + + canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + } + } + + fun start(startScreen: Screen) { + if (started) { + throw IllegalStateException("You can only start a game once!") + } + + setScreen(startScreen) + + // start game loop + started = true + gameLoop() + } + + fun setScreen(screen: Screen) { + currentScreen.unloadResources() + + currentScreen = screen + + screen.loadResources() + } + + fun setClearColor(r: Float, g: Float, b: Float, a: Float) { + clearRed = r + clearGreen = g + clearBlue = b + clearAlpha = a + } + + fun gameLoop() { + try { + if (!Textures.ready()) { + gl().clearColor(1f, 1f, 1f, 1f) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } else { + resize() + + if (!pause) { + html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); + + if (clearScreenEveryFrame) { + gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } + + gl().enable(WebGLRenderingContext.BLEND) + gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); + + val time = Date().getTime() + currentDelta = ((time - currentTime) / 1000f).toFloat() + currentTime = time + + val timeInSeconds = (currentTime - start) / 1000f + + fpsCountTime += currentDelta + fpsCount++ + while (fpsCountTime > 1f) { + fps = fpsCount + fpsCountTime -= 1f + fpsCount = 0 + } + + if (focus) { + currentScreen.update(timeInSeconds.toFloat(), currentDelta) + } + + currentScreen.render() } + } + } catch (e: Exception) { + println("Some error...") + console.log(e) } - fun start(startScreen: Screen) { - if (started) { - throw IllegalStateException("You can only start a game once!") - } - - setScreen(startScreen) - - // start game loop - started = true - gameLoop() + window.requestAnimationFrame { + gameLoop() } - - fun setScreen(screen: Screen) { - currentScreen.unloadResources() - - currentScreen = screen - - screen.loadResources() - } - - fun setClearColor(r: Float, g: Float, b: Float, a: Float) { - clearRed = r - clearGreen = g - clearBlue = b - clearAlpha = a - } - - fun gameLoop() { - try { - if (!Textures.ready()) { - gl().clearColor(1f, 1f, 1f, 1f) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } else { - resize() - - if (!pause) { - html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); - - if (clearScreenEveryFrame) { - gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } - - gl().enable(WebGLRenderingContext.BLEND) - gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); - - val time = Date().getTime() - currentDelta = ((time - currentTime) / 1000f).toFloat() - currentTime = time - - val timeInSeconds = (currentTime - start) / 1000f - - fpsCountTime += currentDelta - fpsCount++ - while (fpsCountTime > 1f) { - fps = fpsCount - fpsCountTime -= 1f - fpsCount = 0 - } - - if (focus) { - currentScreen.update(timeInSeconds.toFloat(), currentDelta) - } - - currentScreen.render() - } - } - } catch(e: Exception) { - println("Some error...") - console.log(e) - } - - window.requestAnimationFrame { - gameLoop() - } - } + } } diff --git a/src/main/kotlin/games/perses/game/Screen.kt b/src/main/kotlin/games/perses/game/Screen.kt index 10b6eae..7b381e7 100644 --- a/src/main/kotlin/games/perses/game/Screen.kt +++ b/src/main/kotlin/games/perses/game/Screen.kt @@ -8,31 +8,31 @@ abstract class Screen { - open fun loadResources() {} + open fun loadResources() {} - @Deprecated( + @Deprecated( message = "replace with unloadResources", replaceWith = ReplaceWith("unloadResources()") - ) - open fun closeResources() { - unloadResources() - } + ) + open fun closeResources() { + unloadResources() + } - open fun unloadResources() {} + open fun unloadResources() {} - abstract fun update(time: Float, delta: Float) + abstract fun update(time: Float, delta: Float) - abstract fun render() + abstract fun render() } -class DefaultScreen: Screen() { - override fun update(time: Float, delta: Float) { - } +class DefaultScreen : Screen() { + override fun update(time: Float, delta: Float) { + } - override fun render() { - // show loading message? - Game.gl().clearColor(1f, 1f, 0f, 1f) - Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } + override fun render() { + // show loading message? + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } } diff --git a/src/main/kotlin/games/perses/game/View.kt b/src/main/kotlin/games/perses/game/View.kt index 540a44d..16c9913 100644 --- a/src/main/kotlin/games/perses/game/View.kt +++ b/src/main/kotlin/games/perses/game/View.kt @@ -4,39 +4,39 @@ import kotlin.browser.document enum class ViewType { - PROJECTION, - WIDTH, - HEIGHT, - ABSOLUTE + PROJECTION, + WIDTH, + HEIGHT, + ABSOLUTE } class View( - var lastWindowWidth: Int = 2000, - var lastWindowHeight: Int = 1000, - var windowWidth: Int = 2000, - var windowHeight: Int = 1000, - var width: Float = 1024f, - var height: Float = 1024f, - var angle: Float = 60f, - var near: Float = -0.1f, - var far: Float = -100f, - var minAspectRatio: Float = 1f, - var maxAspectRatio: Float = 1f, - var leftOffset: Int = 0, - var bottomOffset: Int = 0, - var viewType: ViewType = ViewType.WIDTH, - var drawMode: DrawMode = DrawMode.LINEAR) { - var vMatrix = Matrix4() - var aspectRatio = 1f + var lastWindowWidth: Int = 2000, + var lastWindowHeight: Int = 1000, + var windowWidth: Int = 2000, + var windowHeight: Int = 1000, + var width: Float = 1024f, + var height: Float = 1024f, + var angle: Float = 60f, + var near: Float = -0.1f, + var far: Float = -100f, + var minAspectRatio: Float = 1f, + var maxAspectRatio: Float = 1f, + var leftOffset: Int = 0, + var bottomOffset: Int = 0, + var viewType: ViewType = ViewType.WIDTH, + var drawMode: DrawMode = DrawMode.LINEAR) { + var vMatrix = Matrix4() + var aspectRatio = 1f - init { - updateView() - } + init { + updateView() + } - fun requestFullscreen() { - val element = document.body - //language=javascript - js(""" + fun requestFullscreen() { + val element = document.body + //language=javascript + js(""" if(element.requestFullscreen) { element.requestFullscreen(); } else if(element.mozRequestFullScreen) { @@ -47,10 +47,10 @@ element.msRequestFullscreen(); } """) - } + } - fun exitFullscreen() { - js(""" + fun exitFullscreen() { + js(""" if(document.exitFullscreen) { document.exitFullscreen(); } else if(document.mozCancelFullScreen) { @@ -59,178 +59,178 @@ document.webkitExitFullscreen(); } """) + } + + fun switchFullscreen() { + if (isFullscreen()) { + exitFullscreen() + } else { + requestFullscreen() + } + } + + fun isFullscreen(): Boolean { + val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + + return fse != undefined + } + + fun updateView() { + aspectRatio = windowWidth / windowHeight.toFloat() + + if (aspectRatio < minAspectRatio) { + aspectRatio = minAspectRatio + + windowHeight = (windowWidth / aspectRatio).toInt() } - fun switchFullscreen() { - if (isFullscreen()) { - exitFullscreen() - } else { - requestFullscreen() - } + if (aspectRatio > maxAspectRatio) { + aspectRatio = maxAspectRatio + + windowWidth = (windowHeight * aspectRatio).toInt() } - fun isFullscreen(): Boolean { - val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + when (viewType) { + ViewType.ABSOLUTE -> { + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.WIDTH -> { + height = width / aspectRatio - return fse != undefined + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.HEIGHT -> { + width = height * aspectRatio + + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.PROJECTION -> { + vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun updateView() { - aspectRatio = windowWidth / windowHeight.toFloat() + //println("width: $width, height: $height") + } - if (aspectRatio < minAspectRatio) { - aspectRatio = minAspectRatio + fun screenToGameCoordX(screenX: Float): Float { + var result = screenX - windowHeight = (windowWidth / aspectRatio).toInt() - } - - if (aspectRatio > maxAspectRatio) { - aspectRatio = maxAspectRatio - - windowWidth = (windowHeight * aspectRatio).toInt() - } - - when (viewType) { - ViewType.ABSOLUTE -> { - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.WIDTH -> { - height = width / aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.HEIGHT -> { - width = height * aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.PROJECTION -> { - vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } - - //println("width: $width, height: $height") + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = ((screenX - Game.borderLeft) * width / windowWidth) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordX(screenX: Float): Float { - var result = screenX + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( (screenX - Game.borderLeft) * width / windowWidth ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun screenToGameCoordY(screenY: Float): Float { + var result = screenY - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - ((screenY - Game.borderTop) * height / windowHeight) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordY(screenY: Float): Float { - var result = screenY + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( (screenY - Game.borderTop) * height / windowHeight ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordX(gameX: Float): Float { + var result = gameX + val normalizedX = gameX + (width / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = (gameX / width * windowWidth) + Game.borderLeft + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordX(gameX: Float): Float { - var result = gameX - val normalizedX = gameX + (width / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( gameX / width * windowWidth ) + Game.borderLeft - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordY(gameY: Float): Float { + var result = gameY + val normalizedY = gameY + (height / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - (gameY / height * windowHeight) + Game.borderTop + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordY(gameY: Float): Float { - var result = gameY - val normalizedY = gameY + (height / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( gameY / height * windowHeight ) + Game.borderTop - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun setToWidth(width: Float) { + this.width = width + this.viewType = ViewType.WIDTH - return result - } + updateView() + } - fun setToWidth(width: Float) { - this.width = width - this.viewType = ViewType.WIDTH + fun setToHeight(height: Float) { + this.height = height + this.viewType = ViewType.HEIGHT - updateView() - } + updateView() + } - fun setToHeight(height: Float) { - this.height = height - this.viewType = ViewType.HEIGHT + fun setProjection(angle: Float) { + this.angle = angle + this.viewType = ViewType.PROJECTION - updateView() - } + updateView() + } - fun setProjection(angle: Float) { - this.angle = angle - this.viewType = ViewType.PROJECTION + fun setNear(near: Float) { + this.near = near - updateView() - } + updateView() + } - fun setNear(near: Float) { - this.near = near + fun setFar(far: Float) { + this.far = far - updateView() - } - - fun setFar(far: Float) { - this.far = far - - updateView() - } + updateView() + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/input/Input.kt b/src/main/kotlin/games/perses/input/Input.kt index 71a3adc..58c4f23 100644 --- a/src/main/kotlin/games/perses/input/Input.kt +++ b/src/main/kotlin/games/perses/input/Input.kt @@ -15,235 +15,235 @@ */ enum class KeyCode(val keyCode: Int) { - BACKSPACE(8), - TAB(9), - ENTER(13), - SHIFT(16), - CTRL(17), - ALT(18), - PAUSE_BREAK(19), - CAPS_LOCK(20), - ESCAPE(27), - SPACE(32), - PAGE_UP(33), - PAGE_DOWN(34), - END(35), - HOME(36), - LEFT_ARROW(37), - UP_ARROW(38), - RIGHT_ARROW(39), - DOWN_ARROW(40), - INSERT(45), - DELETE(46), - NR_0(48), - NR_1(49), - NR_2(50), - NR_3(51), - NR_4(52), - NR_5(53), - NR_6(54), - NR_7(55), - NR_8(56), - NR_9(57), - A(65), - B(66), - C(67), - D(68), - E(69), - F(70), - G(71), - H(72), - I(73), - J(74), - K(75), - L(76), - M(77), - N(78), - O(79), - P(80), - Q(81), - R(82), - S(83), - T(84), - U(85), - V(86), - W(87), - X(88), - Y(89), - Z(90), - LEFT_WINDOW_KEY(91), - RIGHT_WINDOW_KEY(92), - SELECT_KEY(93), - NUMPAD_0(96), - NUMPAD_1(97), - NUMPAD_2(98), - NUMPAD_3(99), - NUMPAD_4(100), - NUMPAD_5(101), - NUMPAD_6(102), - NUMPAD_7(103), - NUMPAD_8(104), - NUMPAD_9(105), - MULTIPLY(106), - ADD(107), - SUBTRACT(109), - DECIMAL_POINT(110), - DIVIDE(111), - F1(112), - F2(113), - F3(114), - F4(115), - F5(116), - F6(117), - F7(118), - F8(119), - F9(120), - F10(121), - F11(122), - F12(123), - NUM_LOCK(144), - SCROLL_LOCK(145), - SEMI_COLON(186), - EQUAL_SIGN(187), - COMMA(188), - DASH(189), - PERIOD(190), - FORWARD_SLASH(191), - GRAVE_ACCENT(192), - OPEN_BRACKET(219), - BACK_SLASH(220), - CLOSE_BRAKET(221), - SINGLE_QUOTE(222), + BACKSPACE(8), + TAB(9), + ENTER(13), + SHIFT(16), + CTRL(17), + ALT(18), + PAUSE_BREAK(19), + CAPS_LOCK(20), + ESCAPE(27), + SPACE(32), + PAGE_UP(33), + PAGE_DOWN(34), + END(35), + HOME(36), + LEFT_ARROW(37), + UP_ARROW(38), + RIGHT_ARROW(39), + DOWN_ARROW(40), + INSERT(45), + DELETE(46), + NR_0(48), + NR_1(49), + NR_2(50), + NR_3(51), + NR_4(52), + NR_5(53), + NR_6(54), + NR_7(55), + NR_8(56), + NR_9(57), + A(65), + B(66), + C(67), + D(68), + E(69), + F(70), + G(71), + H(72), + I(73), + J(74), + K(75), + L(76), + M(77), + N(78), + O(79), + P(80), + Q(81), + R(82), + S(83), + T(84), + U(85), + V(86), + W(87), + X(88), + Y(89), + Z(90), + LEFT_WINDOW_KEY(91), + RIGHT_WINDOW_KEY(92), + SELECT_KEY(93), + NUMPAD_0(96), + NUMPAD_1(97), + NUMPAD_2(98), + NUMPAD_3(99), + NUMPAD_4(100), + NUMPAD_5(101), + NUMPAD_6(102), + NUMPAD_7(103), + NUMPAD_8(104), + NUMPAD_9(105), + MULTIPLY(106), + ADD(107), + SUBTRACT(109), + DECIMAL_POINT(110), + DIVIDE(111), + F1(112), + F2(113), + F3(114), + F4(115), + F5(116), + F6(117), + F7(118), + F8(119), + F9(120), + F10(121), + F11(122), + F12(123), + NUM_LOCK(144), + SCROLL_LOCK(145), + SEMI_COLON(186), + EQUAL_SIGN(187), + COMMA(188), + DASH(189), + PERIOD(190), + FORWARD_SLASH(191), + GRAVE_ACCENT(192), + OPEN_BRACKET(219), + BACK_SLASH(220), + CLOSE_BRAKET(221), + SINGLE_QUOTE(222), - ESC(27), - LEFT(37), - UP(38), - DOWN(40), - RIGHT(39), - MINUS(109), - PLUS(107), + ESC(27), + LEFT(37), + UP(38), + DOWN(40), + RIGHT(39), + MINUS(109), + PLUS(107), } interface InputProcessor { - fun keyPressed(charCode: Int) + fun keyPressed(charCode: Int) - fun keyDown(keyCode: Int) + fun keyDown(keyCode: Int) - fun keyUp(keyCode: Int) + fun keyUp(keyCode: Int) - fun pointerClick(pointer: Int, x: Float, y: Float) + fun pointerClick(pointer: Int, x: Float, y: Float) - fun mouseMove(x: Float, y: Float) + fun mouseMove(x: Float, y: Float) } open class EmptyInputProcessor : InputProcessor { - override fun pointerClick(pointer: Int, x: Float, y: Float) { } + override fun pointerClick(pointer: Int, x: Float, y: Float) {} - override fun keyDown(keyCode: Int) { } + override fun keyDown(keyCode: Int) {} - override fun keyPressed(charCode: Int) { } + override fun keyPressed(charCode: Int) {} - override fun keyUp(keyCode: Int) { } + override fun keyUp(keyCode: Int) {} - override fun mouseMove(x: Float, y: Float) { } + override fun mouseMove(x: Float, y: Float) {} } object Input { - private val keys: MutableMap = HashMap() - private var inputProcesser: InputProcessor = EmptyInputProcessor() + private val keys: MutableMap = HashMap() + private var inputProcesser: InputProcessor = EmptyInputProcessor() - init { - val body = document.body - if (body != null) { - body.onkeydown = { - keyDown(it) - } + init { + val body = document.body + if (body != null) { + body.onkeydown = { + keyDown(it) + } - body.onkeyup = { - keyUp(it) - } + body.onkeyup = { + keyUp(it) + } - body.onkeypress = { - keyPress(it) - } + body.onkeypress = { + keyPress(it) + } - body.onclick = { - mouseClick(it) - } + body.onclick = { + mouseClick(it) + } - body.onmousedown = { - mouseMove(it) - } + body.onmousedown = { + mouseMove(it) + } - body.onmouseup = { - mouseMove(it) - } + body.onmouseup = { + mouseMove(it) + } - body.onmousemove = { - mouseMove(it) - } - } else { - console.log("Can't register key events, document.body is null!?") - } + body.onmousemove = { + mouseMove(it) + } + } else { + console.log("Can't register key events, document.body is null!?") } + } - fun setInputProcessor(processor: InputProcessor) { - this.inputProcesser = processor + fun setInputProcessor(processor: InputProcessor) { + this.inputProcesser = processor + } + + private fun keyDown(key: Event) { + if (key is KeyboardEvent) { + keys.put(key.keyCode, Date().getTime()) + + inputProcesser.keyDown(key.keyCode) } + } - private fun keyDown(key: Event) { - if (key is KeyboardEvent) { - keys.put(key.keyCode, Date().getTime()) + private fun keyUp(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyUp(key.keyCode) - inputProcesser.keyDown(key.keyCode) - } + keys.remove(key.keyCode) } + } - private fun keyUp(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyUp(key.keyCode) - - keys.remove(key.keyCode) - } + private fun keyPress(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyPressed(key.charCode) } + } - private fun keyPress(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyPressed(key.charCode) - } + private fun mouseClick(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + + inputProcesser.pointerClick(event.button.toInt(), vx, vy) } + } - private fun mouseClick(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + private fun mouseMove(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) - inputProcesser.pointerClick(event.button.toInt(), vx, vy) - } + inputProcesser.mouseMove(vx, vy) } + } - private fun mouseMove(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + fun isDown(keyCode: Int) = keys.containsKey(keyCode) - inputProcesser.mouseMove(vx, vy) - } - } + fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - fun isDown(keyCode: Int) = keys.containsKey(keyCode) + fun wasPressed(keyCode: Int, delta: Double): Boolean { + val time = keys[keyCode] - fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - - fun wasPressed(keyCode: Int, delta: Double): Boolean { - val time = keys[keyCode] - - return (time != null && time > (Date().getTime() - delta)) - } + return (time != null && time > (Date().getTime() - delta)) + } } diff --git a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt index f1c7808..f3d4126 100644 --- a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt +++ b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt @@ -11,201 +11,201 @@ */ class MapData { - var version: Int = 1 - var properties: MutableMap = HashMap() - var layers: Array? = null - var tilesets: Array? = null + var version: Int = 1 + var properties: MutableMap = HashMap() + var layers: Array? = null + var tilesets: Array? = null - var height: Int = 0 - var width: Int = 0 + var height: Int = 0 + var width: Int = 0 - var nextobjectid: Int = 0 - var orientation: String = "orthogonal" - var renderorder: String = "right-down" - var tileheight: Int = 0 - var tilewidth: Int = 0 + var nextobjectid: Int = 0 + var orientation: String = "orthogonal" + var renderorder: String = "right-down" + var tileheight: Int = 0 + var tilewidth: Int = 0 } class MapLayer { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var data: Array? = null - var encoding: String = "" - var x: Int = 0 - var y: Int = 0 - var width: Int = 0 - var height: Int = 0 - var name: String = "" - var opacity: Float = 1f - var type: String = "" - var visible: Boolean = true - var draworder: String = "" + var data: Array? = null + var encoding: String = "" + var x: Int = 0 + var y: Int = 0 + var width: Int = 0 + var height: Int = 0 + var name: String = "" + var opacity: Float = 1f + var type: String = "" + var visible: Boolean = true + var draworder: String = "" } class MapTileset { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var firstgid: Int = 0 - var image: String = "" - var imageheight: Int = 0 - var imagewidth: Int = 0 - var margin: Int = 0 - var name: String = "" - var spacing: Int = 0 - var tilecount: Int = 0 - var tileheight: Int = 0 - var tilewidth: Int = 0 - var tileproperties: MutableMap> = HashMap() + var firstgid: Int = 0 + var image: String = "" + var imageheight: Int = 0 + var imagewidth: Int = 0 + var margin: Int = 0 + var name: String = "" + var spacing: Int = 0 + var tilecount: Int = 0 + var tileheight: Int = 0 + var tilewidth: Int = 0 + var tileproperties: MutableMap> = HashMap() } class TilesetIndex( - val texture: Texture?, - val tcLeft: Float, - val tcTop: Float, - val tcRight: Float, - val tcBottom: Float, - val scale: Float - ) { - constructor() : this(null, 0f, 0f, 0f, 0f, 0f) + val texture: Texture?, + val tcLeft: Float, + val tcTop: Float, + val tcRight: Float, + val tcBottom: Float, + val scale: Float +) { + constructor() : this(null, 0f, 0f, 0f, 0f, 0f) - fun render(x: Float, y: Float) { - texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) - } + fun render(x: Float, y: Float) { + texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) + } } class TiledMap(dir: String = "", url: String) { - val properties: Map = HashMap() - val data: MapData - val tileset: Array - val tiles: Array - var first = true - //var tilesetIndex: Array = Array(0, { TilesetIndex() }) + val properties: Map = HashMap() + val data: MapData + val tileset: Array + val tiles: Array + var first = true + //var tilesetIndex: Array = Array(0, { TilesetIndex() }) - init { - var tileDir = dir - if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { - tileDir = tileDir + "/" - } - - data = JSON.parse(getUrlAsString(tileDir + url)) - //println("map data is loaded") - val tilesets = data.tilesets - if (tilesets != null) { - tileset = Array(tilesets.size, { "" }) - var maxGid = 0 - for (index in 0..tilesets.size - 1) { - tileset[index] = tilesets[index].name - Textures.load(tilesets[index].name, tileDir + tilesets[index].image) - maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) - } - - tiles = Array(maxGid, { TilesetIndex() }) - } else { - tileset = Array(0, { "" }) - tiles = Array(0, { TilesetIndex() }) - } - - cacheTiles() + init { + var tileDir = dir + if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { + tileDir = tileDir + "/" } - fun cacheTiles() { - if (!Textures.ready()) { - window.setTimeout({ cacheTiles() }, 10) - } else { - val tilesets = data.tilesets - var tcLeft = 0f - var tcTop = 0f - var tcRight = 0f - var tcBottom = 0f + data = JSON.parse(getUrlAsString(tileDir + url)) + //println("map data is loaded") + val tilesets = data.tilesets + if (tilesets != null) { + tileset = Array(tilesets.size, { "" }) + var maxGid = 0 + for (index in 0..tilesets.size - 1) { + tileset[index] = tilesets[index].name + Textures.load(tilesets[index].name, tileDir + tilesets[index].image) + maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) + } - if (tilesets != null) { - - - for (tileset in tilesets) { - val tilesHor = tileset.imagewidth / tileset.tilewidth - val tilesVer = tileset.imageheight / tileset.tileheight - val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) - - for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { - val texture = Textures.get(tileset.name) - - val gid = index - tileset.firstgid - - val xi = gid % tilesHor - var yi = gid / tilesHor - yi = tilesVer - yi - 1 - val tw = 1f / tilesHor.toFloat() - val th = 1f / tilesVer.toFloat() - - val pixelW = 0.1f / tileset.tilewidth - val pixelH = 0.1f / tileset.tileheight - - tcLeft = xi * tw - tcRight = tcLeft + tw - - // switch up/down because of texture coord 0,0 in left bottom corner - tcBottom = yi * th - tcTop = tcBottom + th - - tcLeft += pixelW - tcRight -= pixelW - - tcBottom += pixelH - tcTop -= pixelH - - tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) - } - } - } - } + tiles = Array(maxGid, { TilesetIndex() }) + } else { + tileset = Array(0, { "" }) + tiles = Array(0, { TilesetIndex() }) } - fun drawTile(tile: Int, x: Float, y: Float) { - tiles[tile].render(x, y) + cacheTiles() + } + + fun cacheTiles() { + if (!Textures.ready()) { + window.setTimeout({ cacheTiles() }, 10) + } else { + val tilesets = data.tilesets + var tcLeft = 0f + var tcTop = 0f + var tcRight = 0f + var tcBottom = 0f + + if (tilesets != null) { + + + for (tileset in tilesets) { + val tilesHor = tileset.imagewidth / tileset.tilewidth + val tilesVer = tileset.imageheight / tileset.tileheight + val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) + + for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { + val texture = Textures.get(tileset.name) + + val gid = index - tileset.firstgid + + val xi = gid % tilesHor + var yi = gid / tilesHor + yi = tilesVer - yi - 1 + val tw = 1f / tilesHor.toFloat() + val th = 1f / tilesVer.toFloat() + + val pixelW = 0.1f / tileset.tilewidth + val pixelH = 0.1f / tileset.tileheight + + tcLeft = xi * tw + tcRight = tcLeft + tw + + // switch up/down because of texture coord 0,0 in left bottom corner + tcBottom = yi * th + tcTop = tcBottom + th + + tcLeft += pixelW + tcRight -= pixelW + + tcBottom += pixelH + tcTop -= pixelH + + tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) + } + } + } + } + } + + fun drawTile(tile: Int, x: Float, y: Float) { + tiles[tile].render(x, y) + } + + fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { + var x = 0f + var y = 0f + val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") + val layer = layers[layerIndex] + + val layerData = layer.data + if (layerData != null) { + for (index in layerData.indices) { + // todo: determine if in view + // todo: determine tilewidth + //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { + drawTile(layerData[index], xo + x * 128f, yo + y * 128f) + + when (data.renderorder) { + "right-down" -> { + x++ + if (x >= layer.width) { + x = 0f + y-- + } + } + else -> { + throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") + } + } + //} + } } - fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { - var x = 0f - var y = 0f - val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") - val layer = layers[layerIndex] + val tilesets = data.tilesets + if (tilesets != null) { + for (tileset in tilesets) { + if (Textures.has(tileset.name)) { + val tx = Textures.get(tileset.name) - val layerData = layer.data - if (layerData != null) { - for (index in layerData.indices) { - // todo: determine if in view - // todo: determine tilewidth - //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { - drawTile(layerData[index], xo + x * 128f, yo + y * 128f) - - when (data.renderorder) { - "right-down" -> { - x++ - if (x >= layer.width) { - x = 0f - y-- - } - } - else -> { - throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") - } - } - //} - } + tx.render() } - - val tilesets = data.tilesets - if (tilesets != null) { - for (tileset in tilesets) { - if (Textures.has(tileset.name)) { - val tx = Textures.get(tileset.name) - - tx.render() - } - } - } - - - first = false + } } + + + first = false + } } diff --git a/src/main/kotlin/games/perses/math/Matrix4.kt b/src/main/kotlin/games/perses/math/Matrix4.kt index 7da03cd..bd274bf 100644 --- a/src/main/kotlin/games/perses/math/Matrix4.kt +++ b/src/main/kotlin/games/perses/math/Matrix4.kt @@ -10,184 +10,184 @@ */ class Matrix4 { - internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - internal var temp = FloatArray(16) + internal var temp = FloatArray(16) - private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - fun get(): FloatArray { - return matrix + fun get(): FloatArray { + return matrix + } + + fun getFloat32Array() = Float32Array(get().toTypedArray()) + + fun set(values: FloatArray) { + if (values.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun getFloat32Array() = Float32Array(get().toTypedArray()) + matrix = values + } - fun set(values: FloatArray) { - if (values.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } + fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { + val r = (angle / 180f * Math.PI).toFloat() + val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() - matrix = values + matrix[0] = f / imageAspectRatio + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + + matrix[4] = 0.0f + matrix[5] = f + matrix[6] = 0.0f + matrix[7] = 0.0f + + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = -(far + near) / (far - near) + matrix[11] = -1.0f + + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = -(2.0f * far * near) / (far - near) + matrix[15] = 0.0f + } + + fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { + matrix[0] = 2f / (right - left) + matrix[1] = 0f + matrix[2] = 0f + matrix[3] = 0f + + matrix[4] = 0f + matrix[5] = 2f / (top - bottom) + matrix[6] = 0f + matrix[7] = 0f + + matrix[8] = 0f + matrix[9] = 0f + matrix[10] = -2f / (far - near) + matrix[11] = 0f + + matrix[12] = -(right + left) / (right - left) + matrix[13] = -(top + bottom) / (top - bottom) + matrix[14] = -(far + near) / (far - near) + matrix[15] = 1f + } + + fun setToIdentity() { + matrix[0] = 1.0f + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + matrix[4] = 0.0f + matrix[5] = 1.0f + matrix[6] = 0.0f + matrix[7] = 0.0f + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = 1.0f + matrix[11] = 0.0f + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = 0.0f + matrix[15] = 1.0f + } + + fun mul(other: Matrix4) { + mul(other.get()) + } + + protected fun mul(other: FloatArray) { + if (other.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { - val r = (angle / 180f * Math.PI).toFloat() - val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() + temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] + temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] + temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] + temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] + temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] + temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] + temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] + temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] + temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] + temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] + temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] + temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] + temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] + temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] + temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] + temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - matrix[0] = f / imageAspectRatio - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f + matrix[0] = temp[0] + matrix[1] = temp[1] + matrix[2] = temp[2] + matrix[3] = temp[3] + matrix[4] = temp[4] + matrix[5] = temp[5] + matrix[6] = temp[6] + matrix[7] = temp[7] + matrix[8] = temp[8] + matrix[9] = temp[9] + matrix[10] = temp[10] + matrix[11] = temp[11] + matrix[12] = temp[12] + matrix[13] = temp[13] + matrix[14] = temp[14] + matrix[15] = temp[15] + } - matrix[4] = 0.0f - matrix[5] = f - matrix[6] = 0.0f - matrix[7] = 0.0f + fun translate(x: Float, y: Float, z: Float) { + translateMatrix[12] = x + translateMatrix[13] = y + translateMatrix[14] = z - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = -(far + near) / (far - near) - matrix[11] = -1.0f + mul(translateMatrix) + } - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = -(2.0f * far * near) / (far - near) - matrix[15] = 0.0f - } + fun scale(x: Float, y: Float, z: Float) { + scaleMatrix[0] = x + scaleMatrix[5] = y + scaleMatrix[10] = z - fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { - matrix[0] = 2f / (right - left) - matrix[1] = 0f - matrix[2] = 0f - matrix[3] = 0f + mul(scaleMatrix) + } - matrix[4] = 0f - matrix[5] = 2f / (top - bottom) - matrix[6] = 0f - matrix[7] = 0f + fun rotateX(angle: Float) { + rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() + rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() + rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() + rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - matrix[8] = 0f - matrix[9] = 0f - matrix[10] = -2f / (far - near) - matrix[11] = 0f + mul(rotateXMatrix) + } - matrix[12] = - (right + left) / (right - left) - matrix[13] = - (top + bottom) / (top - bottom) - matrix[14] = - (far + near) / (far - near) - matrix[15] = 1f - } + fun rotateY(angle: Float) { + rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() + rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() + rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - fun setToIdentity() { - matrix[0] = 1.0f - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f - matrix[4] = 0.0f - matrix[5] = 1.0f - matrix[6] = 0.0f - matrix[7] = 0.0f - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = 1.0f - matrix[11] = 0.0f - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = 0.0f - matrix[15] = 1.0f - } + mul(rotateYMatrix) + } - fun mul(other: Matrix4) { - mul(other.get()) - } + fun rotateZ(angle: Float) { + rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() + rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() + rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - protected fun mul(other: FloatArray) { - if (other.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } - - temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] - temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] - temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] - temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] - temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] - temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] - temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] - temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] - temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] - temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] - temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] - temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] - temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] - temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] - temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] - temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - - matrix[0] = temp[0] - matrix[1] = temp[1] - matrix[2] = temp[2] - matrix[3] = temp[3] - matrix[4] = temp[4] - matrix[5] = temp[5] - matrix[6] = temp[6] - matrix[7] = temp[7] - matrix[8] = temp[8] - matrix[9] = temp[9] - matrix[10] = temp[10] - matrix[11] = temp[11] - matrix[12] = temp[12] - matrix[13] = temp[13] - matrix[14] = temp[14] - matrix[15] = temp[15] - } - - fun translate(x: Float, y: Float, z: Float) { - translateMatrix[12] = x - translateMatrix[13] = y - translateMatrix[14] = z - - mul(translateMatrix) - } - - fun scale(x: Float, y: Float, z: Float) { - scaleMatrix[0] = x - scaleMatrix[5] = y - scaleMatrix[10] = z - - mul(scaleMatrix) - } - - fun rotateX(angle: Float) { - rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() - rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() - rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() - rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateXMatrix) - } - - fun rotateY(angle: Float) { - rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() - rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() - rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateYMatrix) - } - - fun rotateZ(angle: Float) { - rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() - rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() - rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateZMatrix) - } + mul(rotateZMatrix) + } } diff --git a/src/main/kotlin/games/perses/net/NetUtils.kt b/src/main/kotlin/games/perses/net/NetUtils.kt index 5b5b820..148b920 100644 --- a/src/main/kotlin/games/perses/net/NetUtils.kt +++ b/src/main/kotlin/games/perses/net/NetUtils.kt @@ -9,10 +9,10 @@ */ fun getUrlAsString(url: String): String { - val req = XMLHttpRequest() + val req = XMLHttpRequest() - req.open("GET", url, false) - req.send(null) + req.open("GET", url, false) + req.send(null) - return req.responseText + return req.responseText } diff --git a/src/main/kotlin/games/perses/shader/ShaderProgram.kt b/src/main/kotlin/games/perses/shader/ShaderProgram.kt index cf07c0f..7dde03a 100644 --- a/src/main/kotlin/games/perses/shader/ShaderProgram.kt +++ b/src/main/kotlin/games/perses/shader/ShaderProgram.kt @@ -1,6 +1,10 @@ package games.perses.shader -import org.khronos.webgl.* +import org.khronos.webgl.Float32Array +import org.khronos.webgl.WebGLBuffer +import org.khronos.webgl.WebGLProgram +import org.khronos.webgl.WebGLRenderingContext +import org.khronos.webgl.WebGLShader /** * User: rnentjes @@ -9,103 +13,125 @@ */ class ShaderProgram( - val webgl: WebGLRenderingContext, - val drawType: Int, - vertexShaderSource: String, - fragmentShaderSource: String, - val vainfo: Array, - val setter: (program: ShaderProgram, data: T) -> Unit) { + val webgl: WebGLRenderingContext, + val drawType: Int, + vertexShaderSource: String, + fragmentShaderSource: String, + val vainfo: Array, + val setter: (program: ShaderProgram, data: T) -> Unit +) { - var shaderProgram: WebGLProgram - var vertex: WebGLShader - var fragment: WebGLShader + var shaderProgram: WebGLProgram + var vertex: WebGLShader + var fragment: WebGLShader - var verticesBlockSize = 0 - var drawLength = 0 + var verticesBlockSize = 0 + var drawLength = 0 - init { - vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER) - fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER) + init { + vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER) + fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER) - shaderProgram = webgl.createProgram() ?: throw IllegalStateException("Unable to request shader program from webgl context!") - webgl.attachShader(shaderProgram, vertex) - webgl.attachShader(shaderProgram, fragment) - webgl.linkProgram(shaderProgram) + shaderProgram = webgl.createProgram() ?: throw IllegalStateException( + "Unable to request shader program from webgl context!" + ) + webgl.attachShader(shaderProgram, vertex) + webgl.attachShader(shaderProgram, fragment) + webgl.linkProgram(shaderProgram) - if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) { - //println(webgl.getProgramInfoLog(shaderProgram)) - throw IllegalStateException("Unable to compile shader program!") - } - - webgl.useProgram(shaderProgram) - - this.verticesBlockSize = 0 - - // set attribute locations... - for (info in vainfo.iterator()) { - info.location = webgl.getAttribLocation(shaderProgram, info.locationName) - info.offset = verticesBlockSize - - verticesBlockSize += info.numElements - //println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}") - } - - when(drawType) { - WebGLRenderingContext.TRIANGLES -> { - drawLength = verticesBlockSize * 3 - } - else -> { - drawLength = verticesBlockSize - } - } - - //println("verticesBlockSize $verticesBlockSize") - - //println("ShaderProgram constructor done") + if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) { + //println(webgl.getProgramInfoLog(shaderProgram)) + throw IllegalStateException("Unable to compile shader program!") } - private fun compileShader(source: String, type: Int): WebGLShader { - val result: WebGLShader = webgl.createShader(type) ?: throw IllegalStateException("Unable to request shader from webgl context!") + webgl.useProgram(shaderProgram) - webgl.shaderSource(result, source) - webgl.compileShader(result) + this.verticesBlockSize = 0 - if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) { - throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}") - } + // set attribute locations... + for (info in vainfo.iterator()) { + info.location = webgl.getAttribLocation(shaderProgram, info.locationName) + info.offset = verticesBlockSize - return result + verticesBlockSize += info.numElements + //println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}") } - fun begin(attribBuffer: WebGLBuffer, userdata: T) { - webgl.useProgram(shaderProgram); - webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); - - // set attribute locations... - for (info in vainfo.iterator()) { - webgl.enableVertexAttribArray(info.location) - webgl.vertexAttribPointer(info.location, info.numElements, WebGLRenderingContext.FLOAT, false, verticesBlockSize * 4, info.offset * 4) - } - - setter(this, userdata) + when (drawType) { + WebGLRenderingContext.TRIANGLES -> { + drawLength = verticesBlockSize * 3 + } + else -> { + drawLength = verticesBlockSize + } } - fun end() { - for (info in vainfo.iterator()) { - webgl.disableVertexAttribArray(info.location); - } - webgl.useProgram(null) + //println("verticesBlockSize $verticesBlockSize") + + //println("ShaderProgram constructor done") + } + + private fun compileShader(source: String, type: Int): WebGLShader { + val result: WebGLShader = webgl.createShader(type) + ?: throw IllegalStateException("Unable to request shader from webgl context!") + + webgl.shaderSource(result, source) + webgl.compileShader(result) + + if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) { + throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}") } - fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location); + return result + } - fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location); + fun begin(attribBuffer: WebGLBuffer, userdata: T) { + webgl.useProgram(shaderProgram); + webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); - fun setUniform1f(location: String, value: Float) { webgl.uniform1f(getUniformLocation(location), value); } - fun setUniform2f(location: String, v1: Float, v2: Float) { webgl.uniform2f(getUniformLocation(location), v1, v2); } - fun setUniform3f(location: String, v1: Float, v2: Float, v3: Float) { webgl.uniform3f(getUniformLocation(location), v1, v2, v3); } - fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); } - fun setUniform1i(location: String, value: Int) { webgl.uniform1i(getUniformLocation(location), value); } - fun setUniformMatrix4fv(location: String, value: Float32Array) { webgl.uniformMatrix4fv(getUniformLocation(location), false, value); } + // set attribute locations... + for (info in vainfo.iterator()) { + webgl.enableVertexAttribArray(info.location) + webgl.vertexAttribPointer( + info.location, + info.numElements, + WebGLRenderingContext.FLOAT, + false, + verticesBlockSize * 4, + info.offset * 4 + ) + } + + setter(this, userdata) + } + + fun end() { + for (info in vainfo.iterator()) { + webgl.disableVertexAttribArray(info.location); + } + webgl.useProgram(null) + } + + fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location); + + fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location); + + fun setUniform1f(location: String, value: Float) { + webgl.uniform1f(getUniformLocation(location), value); } + + fun setUniform2f(location: String, v1: Float, v2: Float) { + webgl.uniform2f(getUniformLocation(location), v1, v2); } + + fun setUniform3f(location: String, v1: Float, v2: Float, v3: Float) { + webgl.uniform3f(getUniformLocation(location), v1, v2, v3); } + + fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { + webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); } + + fun setUniform1i(location: String, value: Int) { + webgl.uniform1i(getUniformLocation(location), value); } + + fun setUniformMatrix4fv(location: String, value: Float32Array) { + webgl.uniformMatrix4fv(getUniformLocation(location), false, value); } } diff --git a/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt b/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt index d9a3908..d65cf7f 100644 --- a/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt +++ b/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt @@ -11,64 +11,67 @@ * Time: 11:57 */ -class VertextAttributeInfo(val locationName: String, val numElements: Int) { - var location = 0 - var offset = 0 +class VertextAttributeInfo( + val locationName: String, + val numElements: Int +) { + var location = 0 + var offset = 0 } class ShaderProgramMesh( - val shaderProgram: ShaderProgram + val shaderProgram: ShaderProgram ) { - val webgl = shaderProgram.webgl - val data: Float32Array = Float32Array(20000 - (20000 % shaderProgram.drawLength)) - var currentIndex: Int = 0 - val attribBuffer: WebGLBuffer - var counter = 0 + val webgl = shaderProgram.webgl + val data: Float32Array = Float32Array(20000 - (20000 % shaderProgram.drawLength)) + var currentIndex: Int = 0 + val attribBuffer: WebGLBuffer + var counter = 0 - init { - attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!") - webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer) + init { + attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!") + webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer) + } + + fun queue(vararg vertices: Float) { + for (vertice in vertices) { + data[currentIndex++] = vertice } - fun queue(vararg vertices: Float) { - for (vertice in vertices) { - data[currentIndex++] = vertice - } - - if (bufferFull()) { - println("Skipped draw call, to many values!") - currentIndex = 0 - } + if (bufferFull()) { + println("Skipped draw call, to many values!") + currentIndex = 0 } + } - fun queueArray(vertices: Array) { - data.set(vertices, currentIndex) - currentIndex += vertices.size + fun queueArray(vertices: Array) { + data.set(vertices, currentIndex) + currentIndex += vertices.size - if (bufferFull()) { - println("Skipped draw call, to many values!") - currentIndex = 0 - } + if (bufferFull()) { + println("Skipped draw call, to many values!") + currentIndex = 0 } + } - fun remaining() = data.length - currentIndex + fun remaining() = data.length - currentIndex - fun bufferFull() = currentIndex == data.length + fun bufferFull() = currentIndex == data.length - fun render(userdata: T) { - counter++ - if (currentIndex > 0) { - if (currentIndex % shaderProgram.verticesBlockSize != 0) { - throw IllegalStateException("Number of vertices not a multiple of the attribute block size!") - } + fun render(userdata: T) { + counter++ + if (currentIndex > 0) { + if (currentIndex % shaderProgram.verticesBlockSize != 0) { + throw IllegalStateException("Number of vertices not a multiple of the attribute block size!") + } - shaderProgram.begin(attribBuffer, userdata) + shaderProgram.begin(attribBuffer, userdata) - webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW) - webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize)) - currentIndex = 0 + webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW) + webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize)) + currentIndex = 0 - shaderProgram.end() - } + shaderProgram.end() } + } } diff --git a/src/main/kotlin/games/perses/sound/Music.kt b/src/main/kotlin/games/perses/sound/Music.kt index a3fcccc..c5ddadf 100644 --- a/src/main/kotlin/games/perses/sound/Music.kt +++ b/src/main/kotlin/games/perses/sound/Music.kt @@ -10,43 +10,43 @@ */ fun HTMLAudioElement.dispose() { - this.pause() - this.parentNode?.removeChild(this) + this.pause() + this.parentNode?.removeChild(this) } object Music { - val playing: MutableSet = HashSet() + val playing: MutableSet = HashSet() - fun load(url: String): HTMLAudioElement { - val audio = document.createElement("audio") as HTMLAudioElement + fun load(url: String): HTMLAudioElement { + val audio = document.createElement("audio") as HTMLAudioElement - audio.src = url + audio.src = url - return audio - } + return audio + } - fun play(url: String, volume: Double = 0.75, looping: Boolean = false): HTMLAudioElement { - val audio = document.createElement("audio") as HTMLAudioElement + fun play(url: String, volume: Double = 0.75, looping: Boolean = false): HTMLAudioElement { + val audio = document.createElement("audio") as HTMLAudioElement - audio.src = url - audio.volume = volume + audio.src = url + audio.volume = volume + audio.play() + + audio.onended = { + if (looping) { + audio.currentTime = 0.0 audio.play() - - audio.onended = { - if (looping) { - audio.currentTime = 0.0 - audio.play() - } else { - //println("REMOVING: $audio") - audio.parentNode?.removeChild(audio) - playing.remove(audio) - } - } - - return audio + } else { + //println("REMOVING: $audio") + audio.parentNode?.removeChild(audio) + playing.remove(audio) + } } - fun stopAll() { + return audio + } - } + fun stopAll() { + + } } diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml index 43edcc2..7ed1494 100644 --- a/.idea/modules/kudens_test.iml +++ b/.idea/modules/kudens_test.iml @@ -1,8 +1,9 @@ - + + $MODULE_DIR$/../../build/kotlinjs/kudens.js \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7ae9969..e7225a0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'perses.games' -version '1.1.6-SNAPSHOT' +version '1.1.7-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'idea' @@ -20,7 +20,7 @@ } buildscript { - ext.kotlin_version = '1.2.21' + ext.kotlin_version = '1.2.30' repositories { maven { url "http://nexus.astraeus.nl/nexus/content/groups/public" diff --git a/src/main/kotlin/games/perses/color/Color.kt b/src/main/kotlin/games/perses/color/Color.kt index 7f235b0..31b540f 100644 --- a/src/main/kotlin/games/perses/color/Color.kt +++ b/src/main/kotlin/games/perses/color/Color.kt @@ -10,107 +10,107 @@ object Color { - /** - * Converts an HSL color value to RGB. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes h, s, and l are contained in the set [0, 1] and - * returns r, g, and b in the set [0, 255]. + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. - * @param h The hue - * * - * @param s The saturation - * * - * @param l The lightness - * * - * @return int array, the RGB representation - */ - fun hslToRgb(h: Float, s: Float, l: Float): IntArray { - val r: Float - val g: Float - val b: Float + * @param h The hue + * * + * @param s The saturation + * * + * @param l The lightness + * * + * @return int array, the RGB representation + */ + fun hslToRgb(h: Float, s: Float, l: Float): IntArray { + val r: Float + val g: Float + val b: Float - if (s == 0f) { - b = l - g = b - r = g // achromatic - } else { - val q = if (l < 0.5f) l * (1 + s) else l + s - l * s - val p = 2 * l - q - r = hueToRgb(p, q, h + 1f / 3f) - g = hueToRgb(p, q, h) - b = hueToRgb(p, q, h - 1f / 3f) - } - val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) + if (s == 0f) { + b = l + g = b + r = g // achromatic + } else { + val q = if (l < 0.5f) l * (1 + s) else l + s - l * s + val p = 2 * l - q + r = hueToRgb(p, q, h + 1f / 3f) + g = hueToRgb(p, q, h) + b = hueToRgb(p, q, h - 1f / 3f) + } + val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) - return rgb + return rgb + } + + /** Helper method that converts hue to rgb */ + fun hueToRgb(p: Float, q: Float, t: Float): Float { + var lt = t + if (lt < 0f) { + lt += 1f + } + if (lt > 1f) { + lt -= 1f + } + if (lt < 1f / 6f) { + return p + (q - p) * 6f * lt + } + if (lt < 1f / 2f) { + return q + } + if (lt < 2f / 3f) { + return p + (q - p) * (2f / 3f - lt) * 6f + } + return p + } + + /** + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes pR, pG, and bpBare contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + + * @param pR The red color value + * * + * @param pG The green color value + * * + * @param pB The blue color value + * * + * @return float array, the HSL representation + */ + fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { + val r = pR / 255f + val g = pG / 255f + val b = pB / 255f + + val max = if (r > g && r > b) r else if (g > b) g else b + val min = if (r < g && r < b) r else if (g < b) g else b + + var h: Float + val s: Float + val l: Float + l = (max + min) / 2.0f + + if (max == min) { + s = 0.0f + h = s + } else { + val d = max - min + s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) + + if (r > g && r > b) + h = (g - b) / d + (if (g < b) 6.0f else 0.0f) + else if (g > b) + h = (b - r) / d + 2.0f + else + h = (r - g) / d + 4.0f + + h /= 6.0f } - /** Helper method that converts hue to rgb */ - fun hueToRgb(p: Float, q: Float, t: Float): Float { - var lt = t - if (lt < 0f) { - lt += 1f - } - if (lt > 1f) { - lt -= 1f - } - if (lt < 1f / 6f) { - return p + (q - p) * 6f * lt - } - if (lt < 1f / 2f) { - return q - } - if (lt < 2f / 3f) { - return p + (q - p) * (2f / 3f - lt) * 6f - } - return p - } - - /** - * Converts an RGB color value to HSL. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes pR, pG, and bpBare contained in the set [0, 255] and - * returns h, s, and l in the set [0, 1]. - - * @param pR The red color value - * * - * @param pG The green color value - * * - * @param pB The blue color value - * * - * @return float array, the HSL representation - */ - fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { - val r = pR / 255f - val g = pG / 255f - val b = pB / 255f - - val max = if (r > g && r > b) r else if (g > b) g else b - val min = if (r < g && r < b) r else if (g < b) g else b - - var h: Float - val s: Float - val l: Float - l = (max + min) / 2.0f - - if (max == min) { - s = 0.0f - h = s - } else { - val d = max - min - s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) - - if (r > g && r > b) - h = (g - b) / d + (if (g < b) 6.0f else 0.0f) - else if (g > b) - h = (b - r) / d + 2.0f - else - h = (r - g) / d + 4.0f - - h /= 6.0f - } - - val hsl = floatArrayOf(h, s, l) - return hsl - } + val hsl = floatArrayOf(h, s, l) + return hsl + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/game/Game.kt b/src/main/kotlin/games/perses/game/Game.kt index 0961316..1becee5 100644 --- a/src/main/kotlin/games/perses/game/Game.kt +++ b/src/main/kotlin/games/perses/game/Game.kt @@ -14,210 +14,210 @@ */ enum class DrawMode { - LINEAR, - NEAREST + LINEAR, + NEAREST } class HTMLElements { - var container: HTMLElement - var webgl: WebGLRenderingContext - var canvas2d: CanvasRenderingContext2D + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D - init { - container = document.createElement("div") as HTMLElement + init { + container = document.createElement("div") as HTMLElement - val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement - val canvas = document.createElement("canvas") as HTMLCanvasElement + val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + val canvas = document.createElement("canvas") as HTMLCanvasElement - container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") - webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" ) - canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" ) + container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;") - document.body!!.appendChild(container) - container.appendChild(webGlCanvas) - container.appendChild(canvas) + document.body!!.appendChild(container) + container.appendChild(webGlCanvas) + container.appendChild(canvas) - val canvas2dcanvas = canvas.getContext("2d") + val canvas2dcanvas = canvas.getContext("2d") - var webglcanvas = webGlCanvas.getContext("webgl") - if (webglcanvas == null) { - console.log("webgl context not found, trying experimental-webgl.") - webglcanvas = webGlCanvas.getContext("experimental-webgl") - } - - if (webglcanvas != null) { - webgl = webglcanvas as WebGLRenderingContext - } else { - console.log("webgl?", webglcanvas) - window.alert("Your browser doesn't seem to support webgl!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } - - if (canvas2dcanvas != null) { - canvas2d = canvas2dcanvas as CanvasRenderingContext2D - } else { - console.log("canvas2d?", canvas2dcanvas) - window.alert("Your browser doesn't seem to support 2d canvas!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } + var webglcanvas = webGlCanvas.getContext("webgl") + if (webglcanvas == null) { + console.log("webgl context not found, trying experimental-webgl.") + webglcanvas = webGlCanvas.getContext("experimental-webgl") } + + if (webglcanvas != null) { + webgl = webglcanvas as WebGLRenderingContext + } else { + console.log("webgl?", webglcanvas) + window.alert("Your browser doesn't seem to support webgl!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + + if (canvas2dcanvas != null) { + canvas2d = canvas2dcanvas as CanvasRenderingContext2D + } else { + console.log("canvas2d?", canvas2dcanvas) + window.alert("Your browser doesn't seem to support 2d canvas!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + } } object Game { - var started = false - val view: View = View() - val html: HTMLElements by lazy { HTMLElements() } - var currentScreen: Screen = DefaultScreen() - var start = Date().getTime() - var currentTime = start - var currentDelta = 0f - var pause: Boolean = false - var clearScreenEveryFrame = true + var started = false + val view: View = View() + val html: HTMLElements by lazy { HTMLElements() } + var currentScreen: Screen = DefaultScreen() + var start = Date().getTime() + var currentTime = start + var currentDelta = 0f + var pause: Boolean = false + var clearScreenEveryFrame = true - var clearRed = 0f - var clearGreen = 0f - var clearBlue = 0f - var clearAlpha = 1f + var clearRed = 0f + var clearGreen = 0f + var clearBlue = 0f + var clearAlpha = 1f - var fps = 0 - var fpsCount = 0 - var fpsCountTime = 0f + var fps = 0 + var fpsCount = 0 + var fpsCountTime = 0f - var borderLeft = 0 - var borderTop = 0 + var borderLeft = 0 + var borderTop = 0 - var focus = true + var focus = true - init { - window.onfocus = { - //println("GOT FOCUS!") + init { + window.onfocus = { + //println("GOT FOCUS!") - focus = true - "" - } - window.onblur = { - //println("LOST FOCUS!") + focus = true + "" + } + window.onblur = { + //println("LOST FOCUS!") - focus = false - "" - } - + focus = false + "" } - fun gl() = html.webgl + } - fun resize() { - val canvas = gl().canvas + fun gl() = html.webgl - // Check if the canvas is not the same size. - val windowWidth = window.innerWidth.toInt() - val windowHeight = window.innerHeight.toInt() + fun resize() { + val canvas = gl().canvas - if (view.lastWindowWidth != windowWidth || - view.lastWindowHeight != windowHeight) { - view.lastWindowWidth = windowWidth - view.lastWindowHeight = windowHeight - view.windowWidth = windowWidth - view.windowHeight = windowHeight + // Check if the canvas is not the same size. + val windowWidth = window.innerWidth.toInt() + val windowHeight = window.innerHeight.toInt() - view.updateView() + if (view.lastWindowWidth != windowWidth || + view.lastWindowHeight != windowHeight) { + view.lastWindowWidth = windowWidth + view.lastWindowHeight = windowHeight + view.windowWidth = windowWidth + view.windowHeight = windowHeight - val textCanvas = html.canvas2d.canvas + view.updateView() - // Make the canvas the same size - canvas.width = view.width.toInt() - canvas.height = view.height.toInt() + val textCanvas = html.canvas2d.canvas - textCanvas.width = view.width.toInt() - textCanvas.height = view.height.toInt() + // Make the canvas the same size + canvas.width = view.width.toInt() + canvas.height = view.height.toInt() - gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) + textCanvas.width = view.width.toInt() + textCanvas.height = view.height.toInt() - borderLeft = (windowWidth - view.windowWidth) / 2 - borderTop = (windowHeight - view.windowHeight) / 2 + gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) - canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) - textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) + borderLeft = (windowWidth - view.windowWidth) / 2 + borderTop = (windowHeight - view.windowHeight) / 2 + + canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + } + } + + fun start(startScreen: Screen) { + if (started) { + throw IllegalStateException("You can only start a game once!") + } + + setScreen(startScreen) + + // start game loop + started = true + gameLoop() + } + + fun setScreen(screen: Screen) { + currentScreen.unloadResources() + + currentScreen = screen + + screen.loadResources() + } + + fun setClearColor(r: Float, g: Float, b: Float, a: Float) { + clearRed = r + clearGreen = g + clearBlue = b + clearAlpha = a + } + + fun gameLoop() { + try { + if (!Textures.ready()) { + gl().clearColor(1f, 1f, 1f, 1f) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } else { + resize() + + if (!pause) { + html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); + + if (clearScreenEveryFrame) { + gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } + + gl().enable(WebGLRenderingContext.BLEND) + gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); + + val time = Date().getTime() + currentDelta = ((time - currentTime) / 1000f).toFloat() + currentTime = time + + val timeInSeconds = (currentTime - start) / 1000f + + fpsCountTime += currentDelta + fpsCount++ + while (fpsCountTime > 1f) { + fps = fpsCount + fpsCountTime -= 1f + fpsCount = 0 + } + + if (focus) { + currentScreen.update(timeInSeconds.toFloat(), currentDelta) + } + + currentScreen.render() } + } + } catch (e: Exception) { + println("Some error...") + console.log(e) } - fun start(startScreen: Screen) { - if (started) { - throw IllegalStateException("You can only start a game once!") - } - - setScreen(startScreen) - - // start game loop - started = true - gameLoop() + window.requestAnimationFrame { + gameLoop() } - - fun setScreen(screen: Screen) { - currentScreen.unloadResources() - - currentScreen = screen - - screen.loadResources() - } - - fun setClearColor(r: Float, g: Float, b: Float, a: Float) { - clearRed = r - clearGreen = g - clearBlue = b - clearAlpha = a - } - - fun gameLoop() { - try { - if (!Textures.ready()) { - gl().clearColor(1f, 1f, 1f, 1f) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } else { - resize() - - if (!pause) { - html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); - - if (clearScreenEveryFrame) { - gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } - - gl().enable(WebGLRenderingContext.BLEND) - gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); - - val time = Date().getTime() - currentDelta = ((time - currentTime) / 1000f).toFloat() - currentTime = time - - val timeInSeconds = (currentTime - start) / 1000f - - fpsCountTime += currentDelta - fpsCount++ - while (fpsCountTime > 1f) { - fps = fpsCount - fpsCountTime -= 1f - fpsCount = 0 - } - - if (focus) { - currentScreen.update(timeInSeconds.toFloat(), currentDelta) - } - - currentScreen.render() - } - } - } catch(e: Exception) { - println("Some error...") - console.log(e) - } - - window.requestAnimationFrame { - gameLoop() - } - } + } } diff --git a/src/main/kotlin/games/perses/game/Screen.kt b/src/main/kotlin/games/perses/game/Screen.kt index 10b6eae..7b381e7 100644 --- a/src/main/kotlin/games/perses/game/Screen.kt +++ b/src/main/kotlin/games/perses/game/Screen.kt @@ -8,31 +8,31 @@ abstract class Screen { - open fun loadResources() {} + open fun loadResources() {} - @Deprecated( + @Deprecated( message = "replace with unloadResources", replaceWith = ReplaceWith("unloadResources()") - ) - open fun closeResources() { - unloadResources() - } + ) + open fun closeResources() { + unloadResources() + } - open fun unloadResources() {} + open fun unloadResources() {} - abstract fun update(time: Float, delta: Float) + abstract fun update(time: Float, delta: Float) - abstract fun render() + abstract fun render() } -class DefaultScreen: Screen() { - override fun update(time: Float, delta: Float) { - } +class DefaultScreen : Screen() { + override fun update(time: Float, delta: Float) { + } - override fun render() { - // show loading message? - Game.gl().clearColor(1f, 1f, 0f, 1f) - Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } + override fun render() { + // show loading message? + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } } diff --git a/src/main/kotlin/games/perses/game/View.kt b/src/main/kotlin/games/perses/game/View.kt index 540a44d..16c9913 100644 --- a/src/main/kotlin/games/perses/game/View.kt +++ b/src/main/kotlin/games/perses/game/View.kt @@ -4,39 +4,39 @@ import kotlin.browser.document enum class ViewType { - PROJECTION, - WIDTH, - HEIGHT, - ABSOLUTE + PROJECTION, + WIDTH, + HEIGHT, + ABSOLUTE } class View( - var lastWindowWidth: Int = 2000, - var lastWindowHeight: Int = 1000, - var windowWidth: Int = 2000, - var windowHeight: Int = 1000, - var width: Float = 1024f, - var height: Float = 1024f, - var angle: Float = 60f, - var near: Float = -0.1f, - var far: Float = -100f, - var minAspectRatio: Float = 1f, - var maxAspectRatio: Float = 1f, - var leftOffset: Int = 0, - var bottomOffset: Int = 0, - var viewType: ViewType = ViewType.WIDTH, - var drawMode: DrawMode = DrawMode.LINEAR) { - var vMatrix = Matrix4() - var aspectRatio = 1f + var lastWindowWidth: Int = 2000, + var lastWindowHeight: Int = 1000, + var windowWidth: Int = 2000, + var windowHeight: Int = 1000, + var width: Float = 1024f, + var height: Float = 1024f, + var angle: Float = 60f, + var near: Float = -0.1f, + var far: Float = -100f, + var minAspectRatio: Float = 1f, + var maxAspectRatio: Float = 1f, + var leftOffset: Int = 0, + var bottomOffset: Int = 0, + var viewType: ViewType = ViewType.WIDTH, + var drawMode: DrawMode = DrawMode.LINEAR) { + var vMatrix = Matrix4() + var aspectRatio = 1f - init { - updateView() - } + init { + updateView() + } - fun requestFullscreen() { - val element = document.body - //language=javascript - js(""" + fun requestFullscreen() { + val element = document.body + //language=javascript + js(""" if(element.requestFullscreen) { element.requestFullscreen(); } else if(element.mozRequestFullScreen) { @@ -47,10 +47,10 @@ element.msRequestFullscreen(); } """) - } + } - fun exitFullscreen() { - js(""" + fun exitFullscreen() { + js(""" if(document.exitFullscreen) { document.exitFullscreen(); } else if(document.mozCancelFullScreen) { @@ -59,178 +59,178 @@ document.webkitExitFullscreen(); } """) + } + + fun switchFullscreen() { + if (isFullscreen()) { + exitFullscreen() + } else { + requestFullscreen() + } + } + + fun isFullscreen(): Boolean { + val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + + return fse != undefined + } + + fun updateView() { + aspectRatio = windowWidth / windowHeight.toFloat() + + if (aspectRatio < minAspectRatio) { + aspectRatio = minAspectRatio + + windowHeight = (windowWidth / aspectRatio).toInt() } - fun switchFullscreen() { - if (isFullscreen()) { - exitFullscreen() - } else { - requestFullscreen() - } + if (aspectRatio > maxAspectRatio) { + aspectRatio = maxAspectRatio + + windowWidth = (windowHeight * aspectRatio).toInt() } - fun isFullscreen(): Boolean { - val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + when (viewType) { + ViewType.ABSOLUTE -> { + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.WIDTH -> { + height = width / aspectRatio - return fse != undefined + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.HEIGHT -> { + width = height * aspectRatio + + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.PROJECTION -> { + vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun updateView() { - aspectRatio = windowWidth / windowHeight.toFloat() + //println("width: $width, height: $height") + } - if (aspectRatio < minAspectRatio) { - aspectRatio = minAspectRatio + fun screenToGameCoordX(screenX: Float): Float { + var result = screenX - windowHeight = (windowWidth / aspectRatio).toInt() - } - - if (aspectRatio > maxAspectRatio) { - aspectRatio = maxAspectRatio - - windowWidth = (windowHeight * aspectRatio).toInt() - } - - when (viewType) { - ViewType.ABSOLUTE -> { - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.WIDTH -> { - height = width / aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.HEIGHT -> { - width = height * aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.PROJECTION -> { - vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } - - //println("width: $width, height: $height") + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = ((screenX - Game.borderLeft) * width / windowWidth) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordX(screenX: Float): Float { - var result = screenX + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( (screenX - Game.borderLeft) * width / windowWidth ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun screenToGameCoordY(screenY: Float): Float { + var result = screenY - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - ((screenY - Game.borderTop) * height / windowHeight) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordY(screenY: Float): Float { - var result = screenY + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( (screenY - Game.borderTop) * height / windowHeight ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordX(gameX: Float): Float { + var result = gameX + val normalizedX = gameX + (width / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = (gameX / width * windowWidth) + Game.borderLeft + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordX(gameX: Float): Float { - var result = gameX - val normalizedX = gameX + (width / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( gameX / width * windowWidth ) + Game.borderLeft - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordY(gameY: Float): Float { + var result = gameY + val normalizedY = gameY + (height / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - (gameY / height * windowHeight) + Game.borderTop + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordY(gameY: Float): Float { - var result = gameY - val normalizedY = gameY + (height / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( gameY / height * windowHeight ) + Game.borderTop - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun setToWidth(width: Float) { + this.width = width + this.viewType = ViewType.WIDTH - return result - } + updateView() + } - fun setToWidth(width: Float) { - this.width = width - this.viewType = ViewType.WIDTH + fun setToHeight(height: Float) { + this.height = height + this.viewType = ViewType.HEIGHT - updateView() - } + updateView() + } - fun setToHeight(height: Float) { - this.height = height - this.viewType = ViewType.HEIGHT + fun setProjection(angle: Float) { + this.angle = angle + this.viewType = ViewType.PROJECTION - updateView() - } + updateView() + } - fun setProjection(angle: Float) { - this.angle = angle - this.viewType = ViewType.PROJECTION + fun setNear(near: Float) { + this.near = near - updateView() - } + updateView() + } - fun setNear(near: Float) { - this.near = near + fun setFar(far: Float) { + this.far = far - updateView() - } - - fun setFar(far: Float) { - this.far = far - - updateView() - } + updateView() + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/input/Input.kt b/src/main/kotlin/games/perses/input/Input.kt index 71a3adc..58c4f23 100644 --- a/src/main/kotlin/games/perses/input/Input.kt +++ b/src/main/kotlin/games/perses/input/Input.kt @@ -15,235 +15,235 @@ */ enum class KeyCode(val keyCode: Int) { - BACKSPACE(8), - TAB(9), - ENTER(13), - SHIFT(16), - CTRL(17), - ALT(18), - PAUSE_BREAK(19), - CAPS_LOCK(20), - ESCAPE(27), - SPACE(32), - PAGE_UP(33), - PAGE_DOWN(34), - END(35), - HOME(36), - LEFT_ARROW(37), - UP_ARROW(38), - RIGHT_ARROW(39), - DOWN_ARROW(40), - INSERT(45), - DELETE(46), - NR_0(48), - NR_1(49), - NR_2(50), - NR_3(51), - NR_4(52), - NR_5(53), - NR_6(54), - NR_7(55), - NR_8(56), - NR_9(57), - A(65), - B(66), - C(67), - D(68), - E(69), - F(70), - G(71), - H(72), - I(73), - J(74), - K(75), - L(76), - M(77), - N(78), - O(79), - P(80), - Q(81), - R(82), - S(83), - T(84), - U(85), - V(86), - W(87), - X(88), - Y(89), - Z(90), - LEFT_WINDOW_KEY(91), - RIGHT_WINDOW_KEY(92), - SELECT_KEY(93), - NUMPAD_0(96), - NUMPAD_1(97), - NUMPAD_2(98), - NUMPAD_3(99), - NUMPAD_4(100), - NUMPAD_5(101), - NUMPAD_6(102), - NUMPAD_7(103), - NUMPAD_8(104), - NUMPAD_9(105), - MULTIPLY(106), - ADD(107), - SUBTRACT(109), - DECIMAL_POINT(110), - DIVIDE(111), - F1(112), - F2(113), - F3(114), - F4(115), - F5(116), - F6(117), - F7(118), - F8(119), - F9(120), - F10(121), - F11(122), - F12(123), - NUM_LOCK(144), - SCROLL_LOCK(145), - SEMI_COLON(186), - EQUAL_SIGN(187), - COMMA(188), - DASH(189), - PERIOD(190), - FORWARD_SLASH(191), - GRAVE_ACCENT(192), - OPEN_BRACKET(219), - BACK_SLASH(220), - CLOSE_BRAKET(221), - SINGLE_QUOTE(222), + BACKSPACE(8), + TAB(9), + ENTER(13), + SHIFT(16), + CTRL(17), + ALT(18), + PAUSE_BREAK(19), + CAPS_LOCK(20), + ESCAPE(27), + SPACE(32), + PAGE_UP(33), + PAGE_DOWN(34), + END(35), + HOME(36), + LEFT_ARROW(37), + UP_ARROW(38), + RIGHT_ARROW(39), + DOWN_ARROW(40), + INSERT(45), + DELETE(46), + NR_0(48), + NR_1(49), + NR_2(50), + NR_3(51), + NR_4(52), + NR_5(53), + NR_6(54), + NR_7(55), + NR_8(56), + NR_9(57), + A(65), + B(66), + C(67), + D(68), + E(69), + F(70), + G(71), + H(72), + I(73), + J(74), + K(75), + L(76), + M(77), + N(78), + O(79), + P(80), + Q(81), + R(82), + S(83), + T(84), + U(85), + V(86), + W(87), + X(88), + Y(89), + Z(90), + LEFT_WINDOW_KEY(91), + RIGHT_WINDOW_KEY(92), + SELECT_KEY(93), + NUMPAD_0(96), + NUMPAD_1(97), + NUMPAD_2(98), + NUMPAD_3(99), + NUMPAD_4(100), + NUMPAD_5(101), + NUMPAD_6(102), + NUMPAD_7(103), + NUMPAD_8(104), + NUMPAD_9(105), + MULTIPLY(106), + ADD(107), + SUBTRACT(109), + DECIMAL_POINT(110), + DIVIDE(111), + F1(112), + F2(113), + F3(114), + F4(115), + F5(116), + F6(117), + F7(118), + F8(119), + F9(120), + F10(121), + F11(122), + F12(123), + NUM_LOCK(144), + SCROLL_LOCK(145), + SEMI_COLON(186), + EQUAL_SIGN(187), + COMMA(188), + DASH(189), + PERIOD(190), + FORWARD_SLASH(191), + GRAVE_ACCENT(192), + OPEN_BRACKET(219), + BACK_SLASH(220), + CLOSE_BRAKET(221), + SINGLE_QUOTE(222), - ESC(27), - LEFT(37), - UP(38), - DOWN(40), - RIGHT(39), - MINUS(109), - PLUS(107), + ESC(27), + LEFT(37), + UP(38), + DOWN(40), + RIGHT(39), + MINUS(109), + PLUS(107), } interface InputProcessor { - fun keyPressed(charCode: Int) + fun keyPressed(charCode: Int) - fun keyDown(keyCode: Int) + fun keyDown(keyCode: Int) - fun keyUp(keyCode: Int) + fun keyUp(keyCode: Int) - fun pointerClick(pointer: Int, x: Float, y: Float) + fun pointerClick(pointer: Int, x: Float, y: Float) - fun mouseMove(x: Float, y: Float) + fun mouseMove(x: Float, y: Float) } open class EmptyInputProcessor : InputProcessor { - override fun pointerClick(pointer: Int, x: Float, y: Float) { } + override fun pointerClick(pointer: Int, x: Float, y: Float) {} - override fun keyDown(keyCode: Int) { } + override fun keyDown(keyCode: Int) {} - override fun keyPressed(charCode: Int) { } + override fun keyPressed(charCode: Int) {} - override fun keyUp(keyCode: Int) { } + override fun keyUp(keyCode: Int) {} - override fun mouseMove(x: Float, y: Float) { } + override fun mouseMove(x: Float, y: Float) {} } object Input { - private val keys: MutableMap = HashMap() - private var inputProcesser: InputProcessor = EmptyInputProcessor() + private val keys: MutableMap = HashMap() + private var inputProcesser: InputProcessor = EmptyInputProcessor() - init { - val body = document.body - if (body != null) { - body.onkeydown = { - keyDown(it) - } + init { + val body = document.body + if (body != null) { + body.onkeydown = { + keyDown(it) + } - body.onkeyup = { - keyUp(it) - } + body.onkeyup = { + keyUp(it) + } - body.onkeypress = { - keyPress(it) - } + body.onkeypress = { + keyPress(it) + } - body.onclick = { - mouseClick(it) - } + body.onclick = { + mouseClick(it) + } - body.onmousedown = { - mouseMove(it) - } + body.onmousedown = { + mouseMove(it) + } - body.onmouseup = { - mouseMove(it) - } + body.onmouseup = { + mouseMove(it) + } - body.onmousemove = { - mouseMove(it) - } - } else { - console.log("Can't register key events, document.body is null!?") - } + body.onmousemove = { + mouseMove(it) + } + } else { + console.log("Can't register key events, document.body is null!?") } + } - fun setInputProcessor(processor: InputProcessor) { - this.inputProcesser = processor + fun setInputProcessor(processor: InputProcessor) { + this.inputProcesser = processor + } + + private fun keyDown(key: Event) { + if (key is KeyboardEvent) { + keys.put(key.keyCode, Date().getTime()) + + inputProcesser.keyDown(key.keyCode) } + } - private fun keyDown(key: Event) { - if (key is KeyboardEvent) { - keys.put(key.keyCode, Date().getTime()) + private fun keyUp(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyUp(key.keyCode) - inputProcesser.keyDown(key.keyCode) - } + keys.remove(key.keyCode) } + } - private fun keyUp(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyUp(key.keyCode) - - keys.remove(key.keyCode) - } + private fun keyPress(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyPressed(key.charCode) } + } - private fun keyPress(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyPressed(key.charCode) - } + private fun mouseClick(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + + inputProcesser.pointerClick(event.button.toInt(), vx, vy) } + } - private fun mouseClick(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + private fun mouseMove(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) - inputProcesser.pointerClick(event.button.toInt(), vx, vy) - } + inputProcesser.mouseMove(vx, vy) } + } - private fun mouseMove(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + fun isDown(keyCode: Int) = keys.containsKey(keyCode) - inputProcesser.mouseMove(vx, vy) - } - } + fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - fun isDown(keyCode: Int) = keys.containsKey(keyCode) + fun wasPressed(keyCode: Int, delta: Double): Boolean { + val time = keys[keyCode] - fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - - fun wasPressed(keyCode: Int, delta: Double): Boolean { - val time = keys[keyCode] - - return (time != null && time > (Date().getTime() - delta)) - } + return (time != null && time > (Date().getTime() - delta)) + } } diff --git a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt index f1c7808..f3d4126 100644 --- a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt +++ b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt @@ -11,201 +11,201 @@ */ class MapData { - var version: Int = 1 - var properties: MutableMap = HashMap() - var layers: Array? = null - var tilesets: Array? = null + var version: Int = 1 + var properties: MutableMap = HashMap() + var layers: Array? = null + var tilesets: Array? = null - var height: Int = 0 - var width: Int = 0 + var height: Int = 0 + var width: Int = 0 - var nextobjectid: Int = 0 - var orientation: String = "orthogonal" - var renderorder: String = "right-down" - var tileheight: Int = 0 - var tilewidth: Int = 0 + var nextobjectid: Int = 0 + var orientation: String = "orthogonal" + var renderorder: String = "right-down" + var tileheight: Int = 0 + var tilewidth: Int = 0 } class MapLayer { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var data: Array? = null - var encoding: String = "" - var x: Int = 0 - var y: Int = 0 - var width: Int = 0 - var height: Int = 0 - var name: String = "" - var opacity: Float = 1f - var type: String = "" - var visible: Boolean = true - var draworder: String = "" + var data: Array? = null + var encoding: String = "" + var x: Int = 0 + var y: Int = 0 + var width: Int = 0 + var height: Int = 0 + var name: String = "" + var opacity: Float = 1f + var type: String = "" + var visible: Boolean = true + var draworder: String = "" } class MapTileset { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var firstgid: Int = 0 - var image: String = "" - var imageheight: Int = 0 - var imagewidth: Int = 0 - var margin: Int = 0 - var name: String = "" - var spacing: Int = 0 - var tilecount: Int = 0 - var tileheight: Int = 0 - var tilewidth: Int = 0 - var tileproperties: MutableMap> = HashMap() + var firstgid: Int = 0 + var image: String = "" + var imageheight: Int = 0 + var imagewidth: Int = 0 + var margin: Int = 0 + var name: String = "" + var spacing: Int = 0 + var tilecount: Int = 0 + var tileheight: Int = 0 + var tilewidth: Int = 0 + var tileproperties: MutableMap> = HashMap() } class TilesetIndex( - val texture: Texture?, - val tcLeft: Float, - val tcTop: Float, - val tcRight: Float, - val tcBottom: Float, - val scale: Float - ) { - constructor() : this(null, 0f, 0f, 0f, 0f, 0f) + val texture: Texture?, + val tcLeft: Float, + val tcTop: Float, + val tcRight: Float, + val tcBottom: Float, + val scale: Float +) { + constructor() : this(null, 0f, 0f, 0f, 0f, 0f) - fun render(x: Float, y: Float) { - texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) - } + fun render(x: Float, y: Float) { + texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) + } } class TiledMap(dir: String = "", url: String) { - val properties: Map = HashMap() - val data: MapData - val tileset: Array - val tiles: Array - var first = true - //var tilesetIndex: Array = Array(0, { TilesetIndex() }) + val properties: Map = HashMap() + val data: MapData + val tileset: Array + val tiles: Array + var first = true + //var tilesetIndex: Array = Array(0, { TilesetIndex() }) - init { - var tileDir = dir - if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { - tileDir = tileDir + "/" - } - - data = JSON.parse(getUrlAsString(tileDir + url)) - //println("map data is loaded") - val tilesets = data.tilesets - if (tilesets != null) { - tileset = Array(tilesets.size, { "" }) - var maxGid = 0 - for (index in 0..tilesets.size - 1) { - tileset[index] = tilesets[index].name - Textures.load(tilesets[index].name, tileDir + tilesets[index].image) - maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) - } - - tiles = Array(maxGid, { TilesetIndex() }) - } else { - tileset = Array(0, { "" }) - tiles = Array(0, { TilesetIndex() }) - } - - cacheTiles() + init { + var tileDir = dir + if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { + tileDir = tileDir + "/" } - fun cacheTiles() { - if (!Textures.ready()) { - window.setTimeout({ cacheTiles() }, 10) - } else { - val tilesets = data.tilesets - var tcLeft = 0f - var tcTop = 0f - var tcRight = 0f - var tcBottom = 0f + data = JSON.parse(getUrlAsString(tileDir + url)) + //println("map data is loaded") + val tilesets = data.tilesets + if (tilesets != null) { + tileset = Array(tilesets.size, { "" }) + var maxGid = 0 + for (index in 0..tilesets.size - 1) { + tileset[index] = tilesets[index].name + Textures.load(tilesets[index].name, tileDir + tilesets[index].image) + maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) + } - if (tilesets != null) { - - - for (tileset in tilesets) { - val tilesHor = tileset.imagewidth / tileset.tilewidth - val tilesVer = tileset.imageheight / tileset.tileheight - val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) - - for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { - val texture = Textures.get(tileset.name) - - val gid = index - tileset.firstgid - - val xi = gid % tilesHor - var yi = gid / tilesHor - yi = tilesVer - yi - 1 - val tw = 1f / tilesHor.toFloat() - val th = 1f / tilesVer.toFloat() - - val pixelW = 0.1f / tileset.tilewidth - val pixelH = 0.1f / tileset.tileheight - - tcLeft = xi * tw - tcRight = tcLeft + tw - - // switch up/down because of texture coord 0,0 in left bottom corner - tcBottom = yi * th - tcTop = tcBottom + th - - tcLeft += pixelW - tcRight -= pixelW - - tcBottom += pixelH - tcTop -= pixelH - - tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) - } - } - } - } + tiles = Array(maxGid, { TilesetIndex() }) + } else { + tileset = Array(0, { "" }) + tiles = Array(0, { TilesetIndex() }) } - fun drawTile(tile: Int, x: Float, y: Float) { - tiles[tile].render(x, y) + cacheTiles() + } + + fun cacheTiles() { + if (!Textures.ready()) { + window.setTimeout({ cacheTiles() }, 10) + } else { + val tilesets = data.tilesets + var tcLeft = 0f + var tcTop = 0f + var tcRight = 0f + var tcBottom = 0f + + if (tilesets != null) { + + + for (tileset in tilesets) { + val tilesHor = tileset.imagewidth / tileset.tilewidth + val tilesVer = tileset.imageheight / tileset.tileheight + val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) + + for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { + val texture = Textures.get(tileset.name) + + val gid = index - tileset.firstgid + + val xi = gid % tilesHor + var yi = gid / tilesHor + yi = tilesVer - yi - 1 + val tw = 1f / tilesHor.toFloat() + val th = 1f / tilesVer.toFloat() + + val pixelW = 0.1f / tileset.tilewidth + val pixelH = 0.1f / tileset.tileheight + + tcLeft = xi * tw + tcRight = tcLeft + tw + + // switch up/down because of texture coord 0,0 in left bottom corner + tcBottom = yi * th + tcTop = tcBottom + th + + tcLeft += pixelW + tcRight -= pixelW + + tcBottom += pixelH + tcTop -= pixelH + + tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) + } + } + } + } + } + + fun drawTile(tile: Int, x: Float, y: Float) { + tiles[tile].render(x, y) + } + + fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { + var x = 0f + var y = 0f + val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") + val layer = layers[layerIndex] + + val layerData = layer.data + if (layerData != null) { + for (index in layerData.indices) { + // todo: determine if in view + // todo: determine tilewidth + //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { + drawTile(layerData[index], xo + x * 128f, yo + y * 128f) + + when (data.renderorder) { + "right-down" -> { + x++ + if (x >= layer.width) { + x = 0f + y-- + } + } + else -> { + throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") + } + } + //} + } } - fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { - var x = 0f - var y = 0f - val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") - val layer = layers[layerIndex] + val tilesets = data.tilesets + if (tilesets != null) { + for (tileset in tilesets) { + if (Textures.has(tileset.name)) { + val tx = Textures.get(tileset.name) - val layerData = layer.data - if (layerData != null) { - for (index in layerData.indices) { - // todo: determine if in view - // todo: determine tilewidth - //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { - drawTile(layerData[index], xo + x * 128f, yo + y * 128f) - - when (data.renderorder) { - "right-down" -> { - x++ - if (x >= layer.width) { - x = 0f - y-- - } - } - else -> { - throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") - } - } - //} - } + tx.render() } - - val tilesets = data.tilesets - if (tilesets != null) { - for (tileset in tilesets) { - if (Textures.has(tileset.name)) { - val tx = Textures.get(tileset.name) - - tx.render() - } - } - } - - - first = false + } } + + + first = false + } } diff --git a/src/main/kotlin/games/perses/math/Matrix4.kt b/src/main/kotlin/games/perses/math/Matrix4.kt index 7da03cd..bd274bf 100644 --- a/src/main/kotlin/games/perses/math/Matrix4.kt +++ b/src/main/kotlin/games/perses/math/Matrix4.kt @@ -10,184 +10,184 @@ */ class Matrix4 { - internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - internal var temp = FloatArray(16) + internal var temp = FloatArray(16) - private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - fun get(): FloatArray { - return matrix + fun get(): FloatArray { + return matrix + } + + fun getFloat32Array() = Float32Array(get().toTypedArray()) + + fun set(values: FloatArray) { + if (values.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun getFloat32Array() = Float32Array(get().toTypedArray()) + matrix = values + } - fun set(values: FloatArray) { - if (values.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } + fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { + val r = (angle / 180f * Math.PI).toFloat() + val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() - matrix = values + matrix[0] = f / imageAspectRatio + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + + matrix[4] = 0.0f + matrix[5] = f + matrix[6] = 0.0f + matrix[7] = 0.0f + + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = -(far + near) / (far - near) + matrix[11] = -1.0f + + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = -(2.0f * far * near) / (far - near) + matrix[15] = 0.0f + } + + fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { + matrix[0] = 2f / (right - left) + matrix[1] = 0f + matrix[2] = 0f + matrix[3] = 0f + + matrix[4] = 0f + matrix[5] = 2f / (top - bottom) + matrix[6] = 0f + matrix[7] = 0f + + matrix[8] = 0f + matrix[9] = 0f + matrix[10] = -2f / (far - near) + matrix[11] = 0f + + matrix[12] = -(right + left) / (right - left) + matrix[13] = -(top + bottom) / (top - bottom) + matrix[14] = -(far + near) / (far - near) + matrix[15] = 1f + } + + fun setToIdentity() { + matrix[0] = 1.0f + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + matrix[4] = 0.0f + matrix[5] = 1.0f + matrix[6] = 0.0f + matrix[7] = 0.0f + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = 1.0f + matrix[11] = 0.0f + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = 0.0f + matrix[15] = 1.0f + } + + fun mul(other: Matrix4) { + mul(other.get()) + } + + protected fun mul(other: FloatArray) { + if (other.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { - val r = (angle / 180f * Math.PI).toFloat() - val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() + temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] + temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] + temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] + temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] + temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] + temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] + temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] + temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] + temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] + temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] + temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] + temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] + temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] + temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] + temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] + temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - matrix[0] = f / imageAspectRatio - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f + matrix[0] = temp[0] + matrix[1] = temp[1] + matrix[2] = temp[2] + matrix[3] = temp[3] + matrix[4] = temp[4] + matrix[5] = temp[5] + matrix[6] = temp[6] + matrix[7] = temp[7] + matrix[8] = temp[8] + matrix[9] = temp[9] + matrix[10] = temp[10] + matrix[11] = temp[11] + matrix[12] = temp[12] + matrix[13] = temp[13] + matrix[14] = temp[14] + matrix[15] = temp[15] + } - matrix[4] = 0.0f - matrix[5] = f - matrix[6] = 0.0f - matrix[7] = 0.0f + fun translate(x: Float, y: Float, z: Float) { + translateMatrix[12] = x + translateMatrix[13] = y + translateMatrix[14] = z - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = -(far + near) / (far - near) - matrix[11] = -1.0f + mul(translateMatrix) + } - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = -(2.0f * far * near) / (far - near) - matrix[15] = 0.0f - } + fun scale(x: Float, y: Float, z: Float) { + scaleMatrix[0] = x + scaleMatrix[5] = y + scaleMatrix[10] = z - fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { - matrix[0] = 2f / (right - left) - matrix[1] = 0f - matrix[2] = 0f - matrix[3] = 0f + mul(scaleMatrix) + } - matrix[4] = 0f - matrix[5] = 2f / (top - bottom) - matrix[6] = 0f - matrix[7] = 0f + fun rotateX(angle: Float) { + rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() + rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() + rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() + rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - matrix[8] = 0f - matrix[9] = 0f - matrix[10] = -2f / (far - near) - matrix[11] = 0f + mul(rotateXMatrix) + } - matrix[12] = - (right + left) / (right - left) - matrix[13] = - (top + bottom) / (top - bottom) - matrix[14] = - (far + near) / (far - near) - matrix[15] = 1f - } + fun rotateY(angle: Float) { + rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() + rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() + rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - fun setToIdentity() { - matrix[0] = 1.0f - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f - matrix[4] = 0.0f - matrix[5] = 1.0f - matrix[6] = 0.0f - matrix[7] = 0.0f - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = 1.0f - matrix[11] = 0.0f - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = 0.0f - matrix[15] = 1.0f - } + mul(rotateYMatrix) + } - fun mul(other: Matrix4) { - mul(other.get()) - } + fun rotateZ(angle: Float) { + rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() + rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() + rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - protected fun mul(other: FloatArray) { - if (other.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } - - temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] - temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] - temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] - temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] - temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] - temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] - temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] - temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] - temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] - temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] - temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] - temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] - temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] - temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] - temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] - temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - - matrix[0] = temp[0] - matrix[1] = temp[1] - matrix[2] = temp[2] - matrix[3] = temp[3] - matrix[4] = temp[4] - matrix[5] = temp[5] - matrix[6] = temp[6] - matrix[7] = temp[7] - matrix[8] = temp[8] - matrix[9] = temp[9] - matrix[10] = temp[10] - matrix[11] = temp[11] - matrix[12] = temp[12] - matrix[13] = temp[13] - matrix[14] = temp[14] - matrix[15] = temp[15] - } - - fun translate(x: Float, y: Float, z: Float) { - translateMatrix[12] = x - translateMatrix[13] = y - translateMatrix[14] = z - - mul(translateMatrix) - } - - fun scale(x: Float, y: Float, z: Float) { - scaleMatrix[0] = x - scaleMatrix[5] = y - scaleMatrix[10] = z - - mul(scaleMatrix) - } - - fun rotateX(angle: Float) { - rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() - rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() - rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() - rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateXMatrix) - } - - fun rotateY(angle: Float) { - rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() - rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() - rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateYMatrix) - } - - fun rotateZ(angle: Float) { - rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() - rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() - rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateZMatrix) - } + mul(rotateZMatrix) + } } diff --git a/src/main/kotlin/games/perses/net/NetUtils.kt b/src/main/kotlin/games/perses/net/NetUtils.kt index 5b5b820..148b920 100644 --- a/src/main/kotlin/games/perses/net/NetUtils.kt +++ b/src/main/kotlin/games/perses/net/NetUtils.kt @@ -9,10 +9,10 @@ */ fun getUrlAsString(url: String): String { - val req = XMLHttpRequest() + val req = XMLHttpRequest() - req.open("GET", url, false) - req.send(null) + req.open("GET", url, false) + req.send(null) - return req.responseText + return req.responseText } diff --git a/src/main/kotlin/games/perses/shader/ShaderProgram.kt b/src/main/kotlin/games/perses/shader/ShaderProgram.kt index cf07c0f..7dde03a 100644 --- a/src/main/kotlin/games/perses/shader/ShaderProgram.kt +++ b/src/main/kotlin/games/perses/shader/ShaderProgram.kt @@ -1,6 +1,10 @@ package games.perses.shader -import org.khronos.webgl.* +import org.khronos.webgl.Float32Array +import org.khronos.webgl.WebGLBuffer +import org.khronos.webgl.WebGLProgram +import org.khronos.webgl.WebGLRenderingContext +import org.khronos.webgl.WebGLShader /** * User: rnentjes @@ -9,103 +13,125 @@ */ class ShaderProgram( - val webgl: WebGLRenderingContext, - val drawType: Int, - vertexShaderSource: String, - fragmentShaderSource: String, - val vainfo: Array, - val setter: (program: ShaderProgram, data: T) -> Unit) { + val webgl: WebGLRenderingContext, + val drawType: Int, + vertexShaderSource: String, + fragmentShaderSource: String, + val vainfo: Array, + val setter: (program: ShaderProgram, data: T) -> Unit +) { - var shaderProgram: WebGLProgram - var vertex: WebGLShader - var fragment: WebGLShader + var shaderProgram: WebGLProgram + var vertex: WebGLShader + var fragment: WebGLShader - var verticesBlockSize = 0 - var drawLength = 0 + var verticesBlockSize = 0 + var drawLength = 0 - init { - vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER) - fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER) + init { + vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER) + fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER) - shaderProgram = webgl.createProgram() ?: throw IllegalStateException("Unable to request shader program from webgl context!") - webgl.attachShader(shaderProgram, vertex) - webgl.attachShader(shaderProgram, fragment) - webgl.linkProgram(shaderProgram) + shaderProgram = webgl.createProgram() ?: throw IllegalStateException( + "Unable to request shader program from webgl context!" + ) + webgl.attachShader(shaderProgram, vertex) + webgl.attachShader(shaderProgram, fragment) + webgl.linkProgram(shaderProgram) - if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) { - //println(webgl.getProgramInfoLog(shaderProgram)) - throw IllegalStateException("Unable to compile shader program!") - } - - webgl.useProgram(shaderProgram) - - this.verticesBlockSize = 0 - - // set attribute locations... - for (info in vainfo.iterator()) { - info.location = webgl.getAttribLocation(shaderProgram, info.locationName) - info.offset = verticesBlockSize - - verticesBlockSize += info.numElements - //println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}") - } - - when(drawType) { - WebGLRenderingContext.TRIANGLES -> { - drawLength = verticesBlockSize * 3 - } - else -> { - drawLength = verticesBlockSize - } - } - - //println("verticesBlockSize $verticesBlockSize") - - //println("ShaderProgram constructor done") + if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) { + //println(webgl.getProgramInfoLog(shaderProgram)) + throw IllegalStateException("Unable to compile shader program!") } - private fun compileShader(source: String, type: Int): WebGLShader { - val result: WebGLShader = webgl.createShader(type) ?: throw IllegalStateException("Unable to request shader from webgl context!") + webgl.useProgram(shaderProgram) - webgl.shaderSource(result, source) - webgl.compileShader(result) + this.verticesBlockSize = 0 - if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) { - throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}") - } + // set attribute locations... + for (info in vainfo.iterator()) { + info.location = webgl.getAttribLocation(shaderProgram, info.locationName) + info.offset = verticesBlockSize - return result + verticesBlockSize += info.numElements + //println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}") } - fun begin(attribBuffer: WebGLBuffer, userdata: T) { - webgl.useProgram(shaderProgram); - webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); - - // set attribute locations... - for (info in vainfo.iterator()) { - webgl.enableVertexAttribArray(info.location) - webgl.vertexAttribPointer(info.location, info.numElements, WebGLRenderingContext.FLOAT, false, verticesBlockSize * 4, info.offset * 4) - } - - setter(this, userdata) + when (drawType) { + WebGLRenderingContext.TRIANGLES -> { + drawLength = verticesBlockSize * 3 + } + else -> { + drawLength = verticesBlockSize + } } - fun end() { - for (info in vainfo.iterator()) { - webgl.disableVertexAttribArray(info.location); - } - webgl.useProgram(null) + //println("verticesBlockSize $verticesBlockSize") + + //println("ShaderProgram constructor done") + } + + private fun compileShader(source: String, type: Int): WebGLShader { + val result: WebGLShader = webgl.createShader(type) + ?: throw IllegalStateException("Unable to request shader from webgl context!") + + webgl.shaderSource(result, source) + webgl.compileShader(result) + + if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) { + throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}") } - fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location); + return result + } - fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location); + fun begin(attribBuffer: WebGLBuffer, userdata: T) { + webgl.useProgram(shaderProgram); + webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); - fun setUniform1f(location: String, value: Float) { webgl.uniform1f(getUniformLocation(location), value); } - fun setUniform2f(location: String, v1: Float, v2: Float) { webgl.uniform2f(getUniformLocation(location), v1, v2); } - fun setUniform3f(location: String, v1: Float, v2: Float, v3: Float) { webgl.uniform3f(getUniformLocation(location), v1, v2, v3); } - fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); } - fun setUniform1i(location: String, value: Int) { webgl.uniform1i(getUniformLocation(location), value); } - fun setUniformMatrix4fv(location: String, value: Float32Array) { webgl.uniformMatrix4fv(getUniformLocation(location), false, value); } + // set attribute locations... + for (info in vainfo.iterator()) { + webgl.enableVertexAttribArray(info.location) + webgl.vertexAttribPointer( + info.location, + info.numElements, + WebGLRenderingContext.FLOAT, + false, + verticesBlockSize * 4, + info.offset * 4 + ) + } + + setter(this, userdata) + } + + fun end() { + for (info in vainfo.iterator()) { + webgl.disableVertexAttribArray(info.location); + } + webgl.useProgram(null) + } + + fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location); + + fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location); + + fun setUniform1f(location: String, value: Float) { + webgl.uniform1f(getUniformLocation(location), value); } + + fun setUniform2f(location: String, v1: Float, v2: Float) { + webgl.uniform2f(getUniformLocation(location), v1, v2); } + + fun setUniform3f(location: String, v1: Float, v2: Float, v3: Float) { + webgl.uniform3f(getUniformLocation(location), v1, v2, v3); } + + fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { + webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); } + + fun setUniform1i(location: String, value: Int) { + webgl.uniform1i(getUniformLocation(location), value); } + + fun setUniformMatrix4fv(location: String, value: Float32Array) { + webgl.uniformMatrix4fv(getUniformLocation(location), false, value); } } diff --git a/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt b/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt index d9a3908..d65cf7f 100644 --- a/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt +++ b/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt @@ -11,64 +11,67 @@ * Time: 11:57 */ -class VertextAttributeInfo(val locationName: String, val numElements: Int) { - var location = 0 - var offset = 0 +class VertextAttributeInfo( + val locationName: String, + val numElements: Int +) { + var location = 0 + var offset = 0 } class ShaderProgramMesh( - val shaderProgram: ShaderProgram + val shaderProgram: ShaderProgram ) { - val webgl = shaderProgram.webgl - val data: Float32Array = Float32Array(20000 - (20000 % shaderProgram.drawLength)) - var currentIndex: Int = 0 - val attribBuffer: WebGLBuffer - var counter = 0 + val webgl = shaderProgram.webgl + val data: Float32Array = Float32Array(20000 - (20000 % shaderProgram.drawLength)) + var currentIndex: Int = 0 + val attribBuffer: WebGLBuffer + var counter = 0 - init { - attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!") - webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer) + init { + attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!") + webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer) + } + + fun queue(vararg vertices: Float) { + for (vertice in vertices) { + data[currentIndex++] = vertice } - fun queue(vararg vertices: Float) { - for (vertice in vertices) { - data[currentIndex++] = vertice - } - - if (bufferFull()) { - println("Skipped draw call, to many values!") - currentIndex = 0 - } + if (bufferFull()) { + println("Skipped draw call, to many values!") + currentIndex = 0 } + } - fun queueArray(vertices: Array) { - data.set(vertices, currentIndex) - currentIndex += vertices.size + fun queueArray(vertices: Array) { + data.set(vertices, currentIndex) + currentIndex += vertices.size - if (bufferFull()) { - println("Skipped draw call, to many values!") - currentIndex = 0 - } + if (bufferFull()) { + println("Skipped draw call, to many values!") + currentIndex = 0 } + } - fun remaining() = data.length - currentIndex + fun remaining() = data.length - currentIndex - fun bufferFull() = currentIndex == data.length + fun bufferFull() = currentIndex == data.length - fun render(userdata: T) { - counter++ - if (currentIndex > 0) { - if (currentIndex % shaderProgram.verticesBlockSize != 0) { - throw IllegalStateException("Number of vertices not a multiple of the attribute block size!") - } + fun render(userdata: T) { + counter++ + if (currentIndex > 0) { + if (currentIndex % shaderProgram.verticesBlockSize != 0) { + throw IllegalStateException("Number of vertices not a multiple of the attribute block size!") + } - shaderProgram.begin(attribBuffer, userdata) + shaderProgram.begin(attribBuffer, userdata) - webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW) - webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize)) - currentIndex = 0 + webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW) + webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize)) + currentIndex = 0 - shaderProgram.end() - } + shaderProgram.end() } + } } diff --git a/src/main/kotlin/games/perses/sound/Music.kt b/src/main/kotlin/games/perses/sound/Music.kt index a3fcccc..c5ddadf 100644 --- a/src/main/kotlin/games/perses/sound/Music.kt +++ b/src/main/kotlin/games/perses/sound/Music.kt @@ -10,43 +10,43 @@ */ fun HTMLAudioElement.dispose() { - this.pause() - this.parentNode?.removeChild(this) + this.pause() + this.parentNode?.removeChild(this) } object Music { - val playing: MutableSet = HashSet() + val playing: MutableSet = HashSet() - fun load(url: String): HTMLAudioElement { - val audio = document.createElement("audio") as HTMLAudioElement + fun load(url: String): HTMLAudioElement { + val audio = document.createElement("audio") as HTMLAudioElement - audio.src = url + audio.src = url - return audio - } + return audio + } - fun play(url: String, volume: Double = 0.75, looping: Boolean = false): HTMLAudioElement { - val audio = document.createElement("audio") as HTMLAudioElement + fun play(url: String, volume: Double = 0.75, looping: Boolean = false): HTMLAudioElement { + val audio = document.createElement("audio") as HTMLAudioElement - audio.src = url - audio.volume = volume + audio.src = url + audio.volume = volume + audio.play() + + audio.onended = { + if (looping) { + audio.currentTime = 0.0 audio.play() - - audio.onended = { - if (looping) { - audio.currentTime = 0.0 - audio.play() - } else { - //println("REMOVING: $audio") - audio.parentNode?.removeChild(audio) - playing.remove(audio) - } - } - - return audio + } else { + //println("REMOVING: $audio") + audio.parentNode?.removeChild(audio) + playing.remove(audio) + } } - fun stopAll() { + return audio + } - } + fun stopAll() { + + } } diff --git a/src/main/kotlin/games/perses/sound/Sounds.kt b/src/main/kotlin/games/perses/sound/Sounds.kt index f866817..f00aa06 100644 --- a/src/main/kotlin/games/perses/sound/Sounds.kt +++ b/src/main/kotlin/games/perses/sound/Sounds.kt @@ -9,83 +9,88 @@ * Time: 12:34 */ -class Sound(val name:String, val url: String, val defaultVolume: Double = 0.75, val numberOfChannels: Int) { - var channels: Array = +class Sound( + val name: String, + val url: String, + val defaultVolume: Double = 0.75, + val numberOfChannels: Int +) { + var channels: Array = Array(numberOfChannels, { document.createElement("audio") as HTMLAudioElement }) - var nextChannel: Int = 0 + var nextChannel: Int = 0 - init { - //println("CREATING: $name") + init { + //println("CREATING: $name") - for (audio in channels) { - if (audio != null) { - audio.src = url - audio.pause() - audio.load() - audio.volume = defaultVolume - } - } + for (audio in channels) { + if (audio != null) { + audio.src = url + audio.pause() + audio.load() + audio.volume = defaultVolume + } } + } - fun play(volume: Double = defaultVolume) { - //println("PLAYING: $name - $nextChannel") - channels[nextChannel]?.volume = volume - channels[nextChannel]?.currentTime = 0.0 - channels[nextChannel]?.play() + fun play(volume: Double = defaultVolume) { + //println("PLAYING: $name - $nextChannel") + channels[nextChannel]?.volume = volume + channels[nextChannel]?.currentTime = 0.0 + channels[nextChannel]?.play() - nextChannel = (nextChannel + 1) % channels.size + nextChannel = (nextChannel + 1) % channels.size + } + + fun pause() { + for (audio in channels) { + audio?.pause() } + } - fun pause() { - for (audio in channels) { - audio?.pause() - } + fun dispose() { + for (audio in channels) { + audio?.dispose() } - - fun dispose() { - for (audio in channels) { - audio?.dispose() - } - } + } } object Sounds { - val sounds: MutableMap = HashMap() + val sounds: MutableMap = HashMap() - fun load(name: String, url: String, volume: Double = 0.75, channels: Int = 1 ) { - sounds.put(name, Sound(name, url, volume, channels)) + fun load(name: String, url: String, volume: Double = 0.75, channels: Int = 1) { + sounds.put(name, Sound(name, url, volume, channels)) + } + + fun play(name: String, volume: Double? = null) { + val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!") + + if (volume != null) { + sound.play(volume) + } else { + sound.play() + } + } + + fun pause(name: String) { + val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!") + + sound.pause() + } + + fun dispose(name: String) { + val sound: Sound? = sounds[name] + + if (sound != null) { + sounds.remove(name) + sound.dispose() + } + } + + fun disposeAll() { + for (sound in sounds.values) { + sound.dispose() } - fun play(name: String, volume: Double? = null) { - val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!") - - if (volume != null) { - sound.play(volume) - } else { - sound.play() - } - } - - fun pause(name: String) { - val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!") - - sound.pause() - } - - fun dispose(name: String) { - val sound: Sound? = sounds[name] - - if (sound != null) { - sounds.remove(name) - sound.dispose() - } - } - - fun disposeAll() { - for (sound in sounds.values) { - sound.dispose() - } - - sounds.clear() - } + sounds.clear() + } } diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml index 43edcc2..7ed1494 100644 --- a/.idea/modules/kudens_test.iml +++ b/.idea/modules/kudens_test.iml @@ -1,8 +1,9 @@ - + + $MODULE_DIR$/../../build/kotlinjs/kudens.js \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7ae9969..e7225a0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'perses.games' -version '1.1.6-SNAPSHOT' +version '1.1.7-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'idea' @@ -20,7 +20,7 @@ } buildscript { - ext.kotlin_version = '1.2.21' + ext.kotlin_version = '1.2.30' repositories { maven { url "http://nexus.astraeus.nl/nexus/content/groups/public" diff --git a/src/main/kotlin/games/perses/color/Color.kt b/src/main/kotlin/games/perses/color/Color.kt index 7f235b0..31b540f 100644 --- a/src/main/kotlin/games/perses/color/Color.kt +++ b/src/main/kotlin/games/perses/color/Color.kt @@ -10,107 +10,107 @@ object Color { - /** - * Converts an HSL color value to RGB. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes h, s, and l are contained in the set [0, 1] and - * returns r, g, and b in the set [0, 255]. + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. - * @param h The hue - * * - * @param s The saturation - * * - * @param l The lightness - * * - * @return int array, the RGB representation - */ - fun hslToRgb(h: Float, s: Float, l: Float): IntArray { - val r: Float - val g: Float - val b: Float + * @param h The hue + * * + * @param s The saturation + * * + * @param l The lightness + * * + * @return int array, the RGB representation + */ + fun hslToRgb(h: Float, s: Float, l: Float): IntArray { + val r: Float + val g: Float + val b: Float - if (s == 0f) { - b = l - g = b - r = g // achromatic - } else { - val q = if (l < 0.5f) l * (1 + s) else l + s - l * s - val p = 2 * l - q - r = hueToRgb(p, q, h + 1f / 3f) - g = hueToRgb(p, q, h) - b = hueToRgb(p, q, h - 1f / 3f) - } - val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) + if (s == 0f) { + b = l + g = b + r = g // achromatic + } else { + val q = if (l < 0.5f) l * (1 + s) else l + s - l * s + val p = 2 * l - q + r = hueToRgb(p, q, h + 1f / 3f) + g = hueToRgb(p, q, h) + b = hueToRgb(p, q, h - 1f / 3f) + } + val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) - return rgb + return rgb + } + + /** Helper method that converts hue to rgb */ + fun hueToRgb(p: Float, q: Float, t: Float): Float { + var lt = t + if (lt < 0f) { + lt += 1f + } + if (lt > 1f) { + lt -= 1f + } + if (lt < 1f / 6f) { + return p + (q - p) * 6f * lt + } + if (lt < 1f / 2f) { + return q + } + if (lt < 2f / 3f) { + return p + (q - p) * (2f / 3f - lt) * 6f + } + return p + } + + /** + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes pR, pG, and bpBare contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + + * @param pR The red color value + * * + * @param pG The green color value + * * + * @param pB The blue color value + * * + * @return float array, the HSL representation + */ + fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { + val r = pR / 255f + val g = pG / 255f + val b = pB / 255f + + val max = if (r > g && r > b) r else if (g > b) g else b + val min = if (r < g && r < b) r else if (g < b) g else b + + var h: Float + val s: Float + val l: Float + l = (max + min) / 2.0f + + if (max == min) { + s = 0.0f + h = s + } else { + val d = max - min + s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) + + if (r > g && r > b) + h = (g - b) / d + (if (g < b) 6.0f else 0.0f) + else if (g > b) + h = (b - r) / d + 2.0f + else + h = (r - g) / d + 4.0f + + h /= 6.0f } - /** Helper method that converts hue to rgb */ - fun hueToRgb(p: Float, q: Float, t: Float): Float { - var lt = t - if (lt < 0f) { - lt += 1f - } - if (lt > 1f) { - lt -= 1f - } - if (lt < 1f / 6f) { - return p + (q - p) * 6f * lt - } - if (lt < 1f / 2f) { - return q - } - if (lt < 2f / 3f) { - return p + (q - p) * (2f / 3f - lt) * 6f - } - return p - } - - /** - * Converts an RGB color value to HSL. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes pR, pG, and bpBare contained in the set [0, 255] and - * returns h, s, and l in the set [0, 1]. - - * @param pR The red color value - * * - * @param pG The green color value - * * - * @param pB The blue color value - * * - * @return float array, the HSL representation - */ - fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { - val r = pR / 255f - val g = pG / 255f - val b = pB / 255f - - val max = if (r > g && r > b) r else if (g > b) g else b - val min = if (r < g && r < b) r else if (g < b) g else b - - var h: Float - val s: Float - val l: Float - l = (max + min) / 2.0f - - if (max == min) { - s = 0.0f - h = s - } else { - val d = max - min - s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) - - if (r > g && r > b) - h = (g - b) / d + (if (g < b) 6.0f else 0.0f) - else if (g > b) - h = (b - r) / d + 2.0f - else - h = (r - g) / d + 4.0f - - h /= 6.0f - } - - val hsl = floatArrayOf(h, s, l) - return hsl - } + val hsl = floatArrayOf(h, s, l) + return hsl + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/game/Game.kt b/src/main/kotlin/games/perses/game/Game.kt index 0961316..1becee5 100644 --- a/src/main/kotlin/games/perses/game/Game.kt +++ b/src/main/kotlin/games/perses/game/Game.kt @@ -14,210 +14,210 @@ */ enum class DrawMode { - LINEAR, - NEAREST + LINEAR, + NEAREST } class HTMLElements { - var container: HTMLElement - var webgl: WebGLRenderingContext - var canvas2d: CanvasRenderingContext2D + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D - init { - container = document.createElement("div") as HTMLElement + init { + container = document.createElement("div") as HTMLElement - val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement - val canvas = document.createElement("canvas") as HTMLCanvasElement + val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + val canvas = document.createElement("canvas") as HTMLCanvasElement - container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") - webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" ) - canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" ) + container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;") - document.body!!.appendChild(container) - container.appendChild(webGlCanvas) - container.appendChild(canvas) + document.body!!.appendChild(container) + container.appendChild(webGlCanvas) + container.appendChild(canvas) - val canvas2dcanvas = canvas.getContext("2d") + val canvas2dcanvas = canvas.getContext("2d") - var webglcanvas = webGlCanvas.getContext("webgl") - if (webglcanvas == null) { - console.log("webgl context not found, trying experimental-webgl.") - webglcanvas = webGlCanvas.getContext("experimental-webgl") - } - - if (webglcanvas != null) { - webgl = webglcanvas as WebGLRenderingContext - } else { - console.log("webgl?", webglcanvas) - window.alert("Your browser doesn't seem to support webgl!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } - - if (canvas2dcanvas != null) { - canvas2d = canvas2dcanvas as CanvasRenderingContext2D - } else { - console.log("canvas2d?", canvas2dcanvas) - window.alert("Your browser doesn't seem to support 2d canvas!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } + var webglcanvas = webGlCanvas.getContext("webgl") + if (webglcanvas == null) { + console.log("webgl context not found, trying experimental-webgl.") + webglcanvas = webGlCanvas.getContext("experimental-webgl") } + + if (webglcanvas != null) { + webgl = webglcanvas as WebGLRenderingContext + } else { + console.log("webgl?", webglcanvas) + window.alert("Your browser doesn't seem to support webgl!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + + if (canvas2dcanvas != null) { + canvas2d = canvas2dcanvas as CanvasRenderingContext2D + } else { + console.log("canvas2d?", canvas2dcanvas) + window.alert("Your browser doesn't seem to support 2d canvas!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + } } object Game { - var started = false - val view: View = View() - val html: HTMLElements by lazy { HTMLElements() } - var currentScreen: Screen = DefaultScreen() - var start = Date().getTime() - var currentTime = start - var currentDelta = 0f - var pause: Boolean = false - var clearScreenEveryFrame = true + var started = false + val view: View = View() + val html: HTMLElements by lazy { HTMLElements() } + var currentScreen: Screen = DefaultScreen() + var start = Date().getTime() + var currentTime = start + var currentDelta = 0f + var pause: Boolean = false + var clearScreenEveryFrame = true - var clearRed = 0f - var clearGreen = 0f - var clearBlue = 0f - var clearAlpha = 1f + var clearRed = 0f + var clearGreen = 0f + var clearBlue = 0f + var clearAlpha = 1f - var fps = 0 - var fpsCount = 0 - var fpsCountTime = 0f + var fps = 0 + var fpsCount = 0 + var fpsCountTime = 0f - var borderLeft = 0 - var borderTop = 0 + var borderLeft = 0 + var borderTop = 0 - var focus = true + var focus = true - init { - window.onfocus = { - //println("GOT FOCUS!") + init { + window.onfocus = { + //println("GOT FOCUS!") - focus = true - "" - } - window.onblur = { - //println("LOST FOCUS!") + focus = true + "" + } + window.onblur = { + //println("LOST FOCUS!") - focus = false - "" - } - + focus = false + "" } - fun gl() = html.webgl + } - fun resize() { - val canvas = gl().canvas + fun gl() = html.webgl - // Check if the canvas is not the same size. - val windowWidth = window.innerWidth.toInt() - val windowHeight = window.innerHeight.toInt() + fun resize() { + val canvas = gl().canvas - if (view.lastWindowWidth != windowWidth || - view.lastWindowHeight != windowHeight) { - view.lastWindowWidth = windowWidth - view.lastWindowHeight = windowHeight - view.windowWidth = windowWidth - view.windowHeight = windowHeight + // Check if the canvas is not the same size. + val windowWidth = window.innerWidth.toInt() + val windowHeight = window.innerHeight.toInt() - view.updateView() + if (view.lastWindowWidth != windowWidth || + view.lastWindowHeight != windowHeight) { + view.lastWindowWidth = windowWidth + view.lastWindowHeight = windowHeight + view.windowWidth = windowWidth + view.windowHeight = windowHeight - val textCanvas = html.canvas2d.canvas + view.updateView() - // Make the canvas the same size - canvas.width = view.width.toInt() - canvas.height = view.height.toInt() + val textCanvas = html.canvas2d.canvas - textCanvas.width = view.width.toInt() - textCanvas.height = view.height.toInt() + // Make the canvas the same size + canvas.width = view.width.toInt() + canvas.height = view.height.toInt() - gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) + textCanvas.width = view.width.toInt() + textCanvas.height = view.height.toInt() - borderLeft = (windowWidth - view.windowWidth) / 2 - borderTop = (windowHeight - view.windowHeight) / 2 + gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) - canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) - textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) + borderLeft = (windowWidth - view.windowWidth) / 2 + borderTop = (windowHeight - view.windowHeight) / 2 + + canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + } + } + + fun start(startScreen: Screen) { + if (started) { + throw IllegalStateException("You can only start a game once!") + } + + setScreen(startScreen) + + // start game loop + started = true + gameLoop() + } + + fun setScreen(screen: Screen) { + currentScreen.unloadResources() + + currentScreen = screen + + screen.loadResources() + } + + fun setClearColor(r: Float, g: Float, b: Float, a: Float) { + clearRed = r + clearGreen = g + clearBlue = b + clearAlpha = a + } + + fun gameLoop() { + try { + if (!Textures.ready()) { + gl().clearColor(1f, 1f, 1f, 1f) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } else { + resize() + + if (!pause) { + html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); + + if (clearScreenEveryFrame) { + gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } + + gl().enable(WebGLRenderingContext.BLEND) + gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); + + val time = Date().getTime() + currentDelta = ((time - currentTime) / 1000f).toFloat() + currentTime = time + + val timeInSeconds = (currentTime - start) / 1000f + + fpsCountTime += currentDelta + fpsCount++ + while (fpsCountTime > 1f) { + fps = fpsCount + fpsCountTime -= 1f + fpsCount = 0 + } + + if (focus) { + currentScreen.update(timeInSeconds.toFloat(), currentDelta) + } + + currentScreen.render() } + } + } catch (e: Exception) { + println("Some error...") + console.log(e) } - fun start(startScreen: Screen) { - if (started) { - throw IllegalStateException("You can only start a game once!") - } - - setScreen(startScreen) - - // start game loop - started = true - gameLoop() + window.requestAnimationFrame { + gameLoop() } - - fun setScreen(screen: Screen) { - currentScreen.unloadResources() - - currentScreen = screen - - screen.loadResources() - } - - fun setClearColor(r: Float, g: Float, b: Float, a: Float) { - clearRed = r - clearGreen = g - clearBlue = b - clearAlpha = a - } - - fun gameLoop() { - try { - if (!Textures.ready()) { - gl().clearColor(1f, 1f, 1f, 1f) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } else { - resize() - - if (!pause) { - html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); - - if (clearScreenEveryFrame) { - gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } - - gl().enable(WebGLRenderingContext.BLEND) - gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); - - val time = Date().getTime() - currentDelta = ((time - currentTime) / 1000f).toFloat() - currentTime = time - - val timeInSeconds = (currentTime - start) / 1000f - - fpsCountTime += currentDelta - fpsCount++ - while (fpsCountTime > 1f) { - fps = fpsCount - fpsCountTime -= 1f - fpsCount = 0 - } - - if (focus) { - currentScreen.update(timeInSeconds.toFloat(), currentDelta) - } - - currentScreen.render() - } - } - } catch(e: Exception) { - println("Some error...") - console.log(e) - } - - window.requestAnimationFrame { - gameLoop() - } - } + } } diff --git a/src/main/kotlin/games/perses/game/Screen.kt b/src/main/kotlin/games/perses/game/Screen.kt index 10b6eae..7b381e7 100644 --- a/src/main/kotlin/games/perses/game/Screen.kt +++ b/src/main/kotlin/games/perses/game/Screen.kt @@ -8,31 +8,31 @@ abstract class Screen { - open fun loadResources() {} + open fun loadResources() {} - @Deprecated( + @Deprecated( message = "replace with unloadResources", replaceWith = ReplaceWith("unloadResources()") - ) - open fun closeResources() { - unloadResources() - } + ) + open fun closeResources() { + unloadResources() + } - open fun unloadResources() {} + open fun unloadResources() {} - abstract fun update(time: Float, delta: Float) + abstract fun update(time: Float, delta: Float) - abstract fun render() + abstract fun render() } -class DefaultScreen: Screen() { - override fun update(time: Float, delta: Float) { - } +class DefaultScreen : Screen() { + override fun update(time: Float, delta: Float) { + } - override fun render() { - // show loading message? - Game.gl().clearColor(1f, 1f, 0f, 1f) - Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } + override fun render() { + // show loading message? + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } } diff --git a/src/main/kotlin/games/perses/game/View.kt b/src/main/kotlin/games/perses/game/View.kt index 540a44d..16c9913 100644 --- a/src/main/kotlin/games/perses/game/View.kt +++ b/src/main/kotlin/games/perses/game/View.kt @@ -4,39 +4,39 @@ import kotlin.browser.document enum class ViewType { - PROJECTION, - WIDTH, - HEIGHT, - ABSOLUTE + PROJECTION, + WIDTH, + HEIGHT, + ABSOLUTE } class View( - var lastWindowWidth: Int = 2000, - var lastWindowHeight: Int = 1000, - var windowWidth: Int = 2000, - var windowHeight: Int = 1000, - var width: Float = 1024f, - var height: Float = 1024f, - var angle: Float = 60f, - var near: Float = -0.1f, - var far: Float = -100f, - var minAspectRatio: Float = 1f, - var maxAspectRatio: Float = 1f, - var leftOffset: Int = 0, - var bottomOffset: Int = 0, - var viewType: ViewType = ViewType.WIDTH, - var drawMode: DrawMode = DrawMode.LINEAR) { - var vMatrix = Matrix4() - var aspectRatio = 1f + var lastWindowWidth: Int = 2000, + var lastWindowHeight: Int = 1000, + var windowWidth: Int = 2000, + var windowHeight: Int = 1000, + var width: Float = 1024f, + var height: Float = 1024f, + var angle: Float = 60f, + var near: Float = -0.1f, + var far: Float = -100f, + var minAspectRatio: Float = 1f, + var maxAspectRatio: Float = 1f, + var leftOffset: Int = 0, + var bottomOffset: Int = 0, + var viewType: ViewType = ViewType.WIDTH, + var drawMode: DrawMode = DrawMode.LINEAR) { + var vMatrix = Matrix4() + var aspectRatio = 1f - init { - updateView() - } + init { + updateView() + } - fun requestFullscreen() { - val element = document.body - //language=javascript - js(""" + fun requestFullscreen() { + val element = document.body + //language=javascript + js(""" if(element.requestFullscreen) { element.requestFullscreen(); } else if(element.mozRequestFullScreen) { @@ -47,10 +47,10 @@ element.msRequestFullscreen(); } """) - } + } - fun exitFullscreen() { - js(""" + fun exitFullscreen() { + js(""" if(document.exitFullscreen) { document.exitFullscreen(); } else if(document.mozCancelFullScreen) { @@ -59,178 +59,178 @@ document.webkitExitFullscreen(); } """) + } + + fun switchFullscreen() { + if (isFullscreen()) { + exitFullscreen() + } else { + requestFullscreen() + } + } + + fun isFullscreen(): Boolean { + val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + + return fse != undefined + } + + fun updateView() { + aspectRatio = windowWidth / windowHeight.toFloat() + + if (aspectRatio < minAspectRatio) { + aspectRatio = minAspectRatio + + windowHeight = (windowWidth / aspectRatio).toInt() } - fun switchFullscreen() { - if (isFullscreen()) { - exitFullscreen() - } else { - requestFullscreen() - } + if (aspectRatio > maxAspectRatio) { + aspectRatio = maxAspectRatio + + windowWidth = (windowHeight * aspectRatio).toInt() } - fun isFullscreen(): Boolean { - val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + when (viewType) { + ViewType.ABSOLUTE -> { + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.WIDTH -> { + height = width / aspectRatio - return fse != undefined + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.HEIGHT -> { + width = height * aspectRatio + + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.PROJECTION -> { + vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun updateView() { - aspectRatio = windowWidth / windowHeight.toFloat() + //println("width: $width, height: $height") + } - if (aspectRatio < minAspectRatio) { - aspectRatio = minAspectRatio + fun screenToGameCoordX(screenX: Float): Float { + var result = screenX - windowHeight = (windowWidth / aspectRatio).toInt() - } - - if (aspectRatio > maxAspectRatio) { - aspectRatio = maxAspectRatio - - windowWidth = (windowHeight * aspectRatio).toInt() - } - - when (viewType) { - ViewType.ABSOLUTE -> { - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.WIDTH -> { - height = width / aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.HEIGHT -> { - width = height * aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.PROJECTION -> { - vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } - - //println("width: $width, height: $height") + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = ((screenX - Game.borderLeft) * width / windowWidth) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordX(screenX: Float): Float { - var result = screenX + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( (screenX - Game.borderLeft) * width / windowWidth ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun screenToGameCoordY(screenY: Float): Float { + var result = screenY - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - ((screenY - Game.borderTop) * height / windowHeight) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordY(screenY: Float): Float { - var result = screenY + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( (screenY - Game.borderTop) * height / windowHeight ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordX(gameX: Float): Float { + var result = gameX + val normalizedX = gameX + (width / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = (gameX / width * windowWidth) + Game.borderLeft + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordX(gameX: Float): Float { - var result = gameX - val normalizedX = gameX + (width / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( gameX / width * windowWidth ) + Game.borderLeft - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordY(gameY: Float): Float { + var result = gameY + val normalizedY = gameY + (height / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - (gameY / height * windowHeight) + Game.borderTop + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordY(gameY: Float): Float { - var result = gameY - val normalizedY = gameY + (height / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( gameY / height * windowHeight ) + Game.borderTop - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun setToWidth(width: Float) { + this.width = width + this.viewType = ViewType.WIDTH - return result - } + updateView() + } - fun setToWidth(width: Float) { - this.width = width - this.viewType = ViewType.WIDTH + fun setToHeight(height: Float) { + this.height = height + this.viewType = ViewType.HEIGHT - updateView() - } + updateView() + } - fun setToHeight(height: Float) { - this.height = height - this.viewType = ViewType.HEIGHT + fun setProjection(angle: Float) { + this.angle = angle + this.viewType = ViewType.PROJECTION - updateView() - } + updateView() + } - fun setProjection(angle: Float) { - this.angle = angle - this.viewType = ViewType.PROJECTION + fun setNear(near: Float) { + this.near = near - updateView() - } + updateView() + } - fun setNear(near: Float) { - this.near = near + fun setFar(far: Float) { + this.far = far - updateView() - } - - fun setFar(far: Float) { - this.far = far - - updateView() - } + updateView() + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/input/Input.kt b/src/main/kotlin/games/perses/input/Input.kt index 71a3adc..58c4f23 100644 --- a/src/main/kotlin/games/perses/input/Input.kt +++ b/src/main/kotlin/games/perses/input/Input.kt @@ -15,235 +15,235 @@ */ enum class KeyCode(val keyCode: Int) { - BACKSPACE(8), - TAB(9), - ENTER(13), - SHIFT(16), - CTRL(17), - ALT(18), - PAUSE_BREAK(19), - CAPS_LOCK(20), - ESCAPE(27), - SPACE(32), - PAGE_UP(33), - PAGE_DOWN(34), - END(35), - HOME(36), - LEFT_ARROW(37), - UP_ARROW(38), - RIGHT_ARROW(39), - DOWN_ARROW(40), - INSERT(45), - DELETE(46), - NR_0(48), - NR_1(49), - NR_2(50), - NR_3(51), - NR_4(52), - NR_5(53), - NR_6(54), - NR_7(55), - NR_8(56), - NR_9(57), - A(65), - B(66), - C(67), - D(68), - E(69), - F(70), - G(71), - H(72), - I(73), - J(74), - K(75), - L(76), - M(77), - N(78), - O(79), - P(80), - Q(81), - R(82), - S(83), - T(84), - U(85), - V(86), - W(87), - X(88), - Y(89), - Z(90), - LEFT_WINDOW_KEY(91), - RIGHT_WINDOW_KEY(92), - SELECT_KEY(93), - NUMPAD_0(96), - NUMPAD_1(97), - NUMPAD_2(98), - NUMPAD_3(99), - NUMPAD_4(100), - NUMPAD_5(101), - NUMPAD_6(102), - NUMPAD_7(103), - NUMPAD_8(104), - NUMPAD_9(105), - MULTIPLY(106), - ADD(107), - SUBTRACT(109), - DECIMAL_POINT(110), - DIVIDE(111), - F1(112), - F2(113), - F3(114), - F4(115), - F5(116), - F6(117), - F7(118), - F8(119), - F9(120), - F10(121), - F11(122), - F12(123), - NUM_LOCK(144), - SCROLL_LOCK(145), - SEMI_COLON(186), - EQUAL_SIGN(187), - COMMA(188), - DASH(189), - PERIOD(190), - FORWARD_SLASH(191), - GRAVE_ACCENT(192), - OPEN_BRACKET(219), - BACK_SLASH(220), - CLOSE_BRAKET(221), - SINGLE_QUOTE(222), + BACKSPACE(8), + TAB(9), + ENTER(13), + SHIFT(16), + CTRL(17), + ALT(18), + PAUSE_BREAK(19), + CAPS_LOCK(20), + ESCAPE(27), + SPACE(32), + PAGE_UP(33), + PAGE_DOWN(34), + END(35), + HOME(36), + LEFT_ARROW(37), + UP_ARROW(38), + RIGHT_ARROW(39), + DOWN_ARROW(40), + INSERT(45), + DELETE(46), + NR_0(48), + NR_1(49), + NR_2(50), + NR_3(51), + NR_4(52), + NR_5(53), + NR_6(54), + NR_7(55), + NR_8(56), + NR_9(57), + A(65), + B(66), + C(67), + D(68), + E(69), + F(70), + G(71), + H(72), + I(73), + J(74), + K(75), + L(76), + M(77), + N(78), + O(79), + P(80), + Q(81), + R(82), + S(83), + T(84), + U(85), + V(86), + W(87), + X(88), + Y(89), + Z(90), + LEFT_WINDOW_KEY(91), + RIGHT_WINDOW_KEY(92), + SELECT_KEY(93), + NUMPAD_0(96), + NUMPAD_1(97), + NUMPAD_2(98), + NUMPAD_3(99), + NUMPAD_4(100), + NUMPAD_5(101), + NUMPAD_6(102), + NUMPAD_7(103), + NUMPAD_8(104), + NUMPAD_9(105), + MULTIPLY(106), + ADD(107), + SUBTRACT(109), + DECIMAL_POINT(110), + DIVIDE(111), + F1(112), + F2(113), + F3(114), + F4(115), + F5(116), + F6(117), + F7(118), + F8(119), + F9(120), + F10(121), + F11(122), + F12(123), + NUM_LOCK(144), + SCROLL_LOCK(145), + SEMI_COLON(186), + EQUAL_SIGN(187), + COMMA(188), + DASH(189), + PERIOD(190), + FORWARD_SLASH(191), + GRAVE_ACCENT(192), + OPEN_BRACKET(219), + BACK_SLASH(220), + CLOSE_BRAKET(221), + SINGLE_QUOTE(222), - ESC(27), - LEFT(37), - UP(38), - DOWN(40), - RIGHT(39), - MINUS(109), - PLUS(107), + ESC(27), + LEFT(37), + UP(38), + DOWN(40), + RIGHT(39), + MINUS(109), + PLUS(107), } interface InputProcessor { - fun keyPressed(charCode: Int) + fun keyPressed(charCode: Int) - fun keyDown(keyCode: Int) + fun keyDown(keyCode: Int) - fun keyUp(keyCode: Int) + fun keyUp(keyCode: Int) - fun pointerClick(pointer: Int, x: Float, y: Float) + fun pointerClick(pointer: Int, x: Float, y: Float) - fun mouseMove(x: Float, y: Float) + fun mouseMove(x: Float, y: Float) } open class EmptyInputProcessor : InputProcessor { - override fun pointerClick(pointer: Int, x: Float, y: Float) { } + override fun pointerClick(pointer: Int, x: Float, y: Float) {} - override fun keyDown(keyCode: Int) { } + override fun keyDown(keyCode: Int) {} - override fun keyPressed(charCode: Int) { } + override fun keyPressed(charCode: Int) {} - override fun keyUp(keyCode: Int) { } + override fun keyUp(keyCode: Int) {} - override fun mouseMove(x: Float, y: Float) { } + override fun mouseMove(x: Float, y: Float) {} } object Input { - private val keys: MutableMap = HashMap() - private var inputProcesser: InputProcessor = EmptyInputProcessor() + private val keys: MutableMap = HashMap() + private var inputProcesser: InputProcessor = EmptyInputProcessor() - init { - val body = document.body - if (body != null) { - body.onkeydown = { - keyDown(it) - } + init { + val body = document.body + if (body != null) { + body.onkeydown = { + keyDown(it) + } - body.onkeyup = { - keyUp(it) - } + body.onkeyup = { + keyUp(it) + } - body.onkeypress = { - keyPress(it) - } + body.onkeypress = { + keyPress(it) + } - body.onclick = { - mouseClick(it) - } + body.onclick = { + mouseClick(it) + } - body.onmousedown = { - mouseMove(it) - } + body.onmousedown = { + mouseMove(it) + } - body.onmouseup = { - mouseMove(it) - } + body.onmouseup = { + mouseMove(it) + } - body.onmousemove = { - mouseMove(it) - } - } else { - console.log("Can't register key events, document.body is null!?") - } + body.onmousemove = { + mouseMove(it) + } + } else { + console.log("Can't register key events, document.body is null!?") } + } - fun setInputProcessor(processor: InputProcessor) { - this.inputProcesser = processor + fun setInputProcessor(processor: InputProcessor) { + this.inputProcesser = processor + } + + private fun keyDown(key: Event) { + if (key is KeyboardEvent) { + keys.put(key.keyCode, Date().getTime()) + + inputProcesser.keyDown(key.keyCode) } + } - private fun keyDown(key: Event) { - if (key is KeyboardEvent) { - keys.put(key.keyCode, Date().getTime()) + private fun keyUp(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyUp(key.keyCode) - inputProcesser.keyDown(key.keyCode) - } + keys.remove(key.keyCode) } + } - private fun keyUp(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyUp(key.keyCode) - - keys.remove(key.keyCode) - } + private fun keyPress(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyPressed(key.charCode) } + } - private fun keyPress(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyPressed(key.charCode) - } + private fun mouseClick(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + + inputProcesser.pointerClick(event.button.toInt(), vx, vy) } + } - private fun mouseClick(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + private fun mouseMove(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) - inputProcesser.pointerClick(event.button.toInt(), vx, vy) - } + inputProcesser.mouseMove(vx, vy) } + } - private fun mouseMove(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + fun isDown(keyCode: Int) = keys.containsKey(keyCode) - inputProcesser.mouseMove(vx, vy) - } - } + fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - fun isDown(keyCode: Int) = keys.containsKey(keyCode) + fun wasPressed(keyCode: Int, delta: Double): Boolean { + val time = keys[keyCode] - fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - - fun wasPressed(keyCode: Int, delta: Double): Boolean { - val time = keys[keyCode] - - return (time != null && time > (Date().getTime() - delta)) - } + return (time != null && time > (Date().getTime() - delta)) + } } diff --git a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt index f1c7808..f3d4126 100644 --- a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt +++ b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt @@ -11,201 +11,201 @@ */ class MapData { - var version: Int = 1 - var properties: MutableMap = HashMap() - var layers: Array? = null - var tilesets: Array? = null + var version: Int = 1 + var properties: MutableMap = HashMap() + var layers: Array? = null + var tilesets: Array? = null - var height: Int = 0 - var width: Int = 0 + var height: Int = 0 + var width: Int = 0 - var nextobjectid: Int = 0 - var orientation: String = "orthogonal" - var renderorder: String = "right-down" - var tileheight: Int = 0 - var tilewidth: Int = 0 + var nextobjectid: Int = 0 + var orientation: String = "orthogonal" + var renderorder: String = "right-down" + var tileheight: Int = 0 + var tilewidth: Int = 0 } class MapLayer { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var data: Array? = null - var encoding: String = "" - var x: Int = 0 - var y: Int = 0 - var width: Int = 0 - var height: Int = 0 - var name: String = "" - var opacity: Float = 1f - var type: String = "" - var visible: Boolean = true - var draworder: String = "" + var data: Array? = null + var encoding: String = "" + var x: Int = 0 + var y: Int = 0 + var width: Int = 0 + var height: Int = 0 + var name: String = "" + var opacity: Float = 1f + var type: String = "" + var visible: Boolean = true + var draworder: String = "" } class MapTileset { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var firstgid: Int = 0 - var image: String = "" - var imageheight: Int = 0 - var imagewidth: Int = 0 - var margin: Int = 0 - var name: String = "" - var spacing: Int = 0 - var tilecount: Int = 0 - var tileheight: Int = 0 - var tilewidth: Int = 0 - var tileproperties: MutableMap> = HashMap() + var firstgid: Int = 0 + var image: String = "" + var imageheight: Int = 0 + var imagewidth: Int = 0 + var margin: Int = 0 + var name: String = "" + var spacing: Int = 0 + var tilecount: Int = 0 + var tileheight: Int = 0 + var tilewidth: Int = 0 + var tileproperties: MutableMap> = HashMap() } class TilesetIndex( - val texture: Texture?, - val tcLeft: Float, - val tcTop: Float, - val tcRight: Float, - val tcBottom: Float, - val scale: Float - ) { - constructor() : this(null, 0f, 0f, 0f, 0f, 0f) + val texture: Texture?, + val tcLeft: Float, + val tcTop: Float, + val tcRight: Float, + val tcBottom: Float, + val scale: Float +) { + constructor() : this(null, 0f, 0f, 0f, 0f, 0f) - fun render(x: Float, y: Float) { - texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) - } + fun render(x: Float, y: Float) { + texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) + } } class TiledMap(dir: String = "", url: String) { - val properties: Map = HashMap() - val data: MapData - val tileset: Array - val tiles: Array - var first = true - //var tilesetIndex: Array = Array(0, { TilesetIndex() }) + val properties: Map = HashMap() + val data: MapData + val tileset: Array + val tiles: Array + var first = true + //var tilesetIndex: Array = Array(0, { TilesetIndex() }) - init { - var tileDir = dir - if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { - tileDir = tileDir + "/" - } - - data = JSON.parse(getUrlAsString(tileDir + url)) - //println("map data is loaded") - val tilesets = data.tilesets - if (tilesets != null) { - tileset = Array(tilesets.size, { "" }) - var maxGid = 0 - for (index in 0..tilesets.size - 1) { - tileset[index] = tilesets[index].name - Textures.load(tilesets[index].name, tileDir + tilesets[index].image) - maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) - } - - tiles = Array(maxGid, { TilesetIndex() }) - } else { - tileset = Array(0, { "" }) - tiles = Array(0, { TilesetIndex() }) - } - - cacheTiles() + init { + var tileDir = dir + if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { + tileDir = tileDir + "/" } - fun cacheTiles() { - if (!Textures.ready()) { - window.setTimeout({ cacheTiles() }, 10) - } else { - val tilesets = data.tilesets - var tcLeft = 0f - var tcTop = 0f - var tcRight = 0f - var tcBottom = 0f + data = JSON.parse(getUrlAsString(tileDir + url)) + //println("map data is loaded") + val tilesets = data.tilesets + if (tilesets != null) { + tileset = Array(tilesets.size, { "" }) + var maxGid = 0 + for (index in 0..tilesets.size - 1) { + tileset[index] = tilesets[index].name + Textures.load(tilesets[index].name, tileDir + tilesets[index].image) + maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) + } - if (tilesets != null) { - - - for (tileset in tilesets) { - val tilesHor = tileset.imagewidth / tileset.tilewidth - val tilesVer = tileset.imageheight / tileset.tileheight - val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) - - for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { - val texture = Textures.get(tileset.name) - - val gid = index - tileset.firstgid - - val xi = gid % tilesHor - var yi = gid / tilesHor - yi = tilesVer - yi - 1 - val tw = 1f / tilesHor.toFloat() - val th = 1f / tilesVer.toFloat() - - val pixelW = 0.1f / tileset.tilewidth - val pixelH = 0.1f / tileset.tileheight - - tcLeft = xi * tw - tcRight = tcLeft + tw - - // switch up/down because of texture coord 0,0 in left bottom corner - tcBottom = yi * th - tcTop = tcBottom + th - - tcLeft += pixelW - tcRight -= pixelW - - tcBottom += pixelH - tcTop -= pixelH - - tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) - } - } - } - } + tiles = Array(maxGid, { TilesetIndex() }) + } else { + tileset = Array(0, { "" }) + tiles = Array(0, { TilesetIndex() }) } - fun drawTile(tile: Int, x: Float, y: Float) { - tiles[tile].render(x, y) + cacheTiles() + } + + fun cacheTiles() { + if (!Textures.ready()) { + window.setTimeout({ cacheTiles() }, 10) + } else { + val tilesets = data.tilesets + var tcLeft = 0f + var tcTop = 0f + var tcRight = 0f + var tcBottom = 0f + + if (tilesets != null) { + + + for (tileset in tilesets) { + val tilesHor = tileset.imagewidth / tileset.tilewidth + val tilesVer = tileset.imageheight / tileset.tileheight + val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) + + for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { + val texture = Textures.get(tileset.name) + + val gid = index - tileset.firstgid + + val xi = gid % tilesHor + var yi = gid / tilesHor + yi = tilesVer - yi - 1 + val tw = 1f / tilesHor.toFloat() + val th = 1f / tilesVer.toFloat() + + val pixelW = 0.1f / tileset.tilewidth + val pixelH = 0.1f / tileset.tileheight + + tcLeft = xi * tw + tcRight = tcLeft + tw + + // switch up/down because of texture coord 0,0 in left bottom corner + tcBottom = yi * th + tcTop = tcBottom + th + + tcLeft += pixelW + tcRight -= pixelW + + tcBottom += pixelH + tcTop -= pixelH + + tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) + } + } + } + } + } + + fun drawTile(tile: Int, x: Float, y: Float) { + tiles[tile].render(x, y) + } + + fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { + var x = 0f + var y = 0f + val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") + val layer = layers[layerIndex] + + val layerData = layer.data + if (layerData != null) { + for (index in layerData.indices) { + // todo: determine if in view + // todo: determine tilewidth + //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { + drawTile(layerData[index], xo + x * 128f, yo + y * 128f) + + when (data.renderorder) { + "right-down" -> { + x++ + if (x >= layer.width) { + x = 0f + y-- + } + } + else -> { + throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") + } + } + //} + } } - fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { - var x = 0f - var y = 0f - val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") - val layer = layers[layerIndex] + val tilesets = data.tilesets + if (tilesets != null) { + for (tileset in tilesets) { + if (Textures.has(tileset.name)) { + val tx = Textures.get(tileset.name) - val layerData = layer.data - if (layerData != null) { - for (index in layerData.indices) { - // todo: determine if in view - // todo: determine tilewidth - //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { - drawTile(layerData[index], xo + x * 128f, yo + y * 128f) - - when (data.renderorder) { - "right-down" -> { - x++ - if (x >= layer.width) { - x = 0f - y-- - } - } - else -> { - throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") - } - } - //} - } + tx.render() } - - val tilesets = data.tilesets - if (tilesets != null) { - for (tileset in tilesets) { - if (Textures.has(tileset.name)) { - val tx = Textures.get(tileset.name) - - tx.render() - } - } - } - - - first = false + } } + + + first = false + } } diff --git a/src/main/kotlin/games/perses/math/Matrix4.kt b/src/main/kotlin/games/perses/math/Matrix4.kt index 7da03cd..bd274bf 100644 --- a/src/main/kotlin/games/perses/math/Matrix4.kt +++ b/src/main/kotlin/games/perses/math/Matrix4.kt @@ -10,184 +10,184 @@ */ class Matrix4 { - internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - internal var temp = FloatArray(16) + internal var temp = FloatArray(16) - private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - fun get(): FloatArray { - return matrix + fun get(): FloatArray { + return matrix + } + + fun getFloat32Array() = Float32Array(get().toTypedArray()) + + fun set(values: FloatArray) { + if (values.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun getFloat32Array() = Float32Array(get().toTypedArray()) + matrix = values + } - fun set(values: FloatArray) { - if (values.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } + fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { + val r = (angle / 180f * Math.PI).toFloat() + val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() - matrix = values + matrix[0] = f / imageAspectRatio + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + + matrix[4] = 0.0f + matrix[5] = f + matrix[6] = 0.0f + matrix[7] = 0.0f + + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = -(far + near) / (far - near) + matrix[11] = -1.0f + + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = -(2.0f * far * near) / (far - near) + matrix[15] = 0.0f + } + + fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { + matrix[0] = 2f / (right - left) + matrix[1] = 0f + matrix[2] = 0f + matrix[3] = 0f + + matrix[4] = 0f + matrix[5] = 2f / (top - bottom) + matrix[6] = 0f + matrix[7] = 0f + + matrix[8] = 0f + matrix[9] = 0f + matrix[10] = -2f / (far - near) + matrix[11] = 0f + + matrix[12] = -(right + left) / (right - left) + matrix[13] = -(top + bottom) / (top - bottom) + matrix[14] = -(far + near) / (far - near) + matrix[15] = 1f + } + + fun setToIdentity() { + matrix[0] = 1.0f + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + matrix[4] = 0.0f + matrix[5] = 1.0f + matrix[6] = 0.0f + matrix[7] = 0.0f + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = 1.0f + matrix[11] = 0.0f + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = 0.0f + matrix[15] = 1.0f + } + + fun mul(other: Matrix4) { + mul(other.get()) + } + + protected fun mul(other: FloatArray) { + if (other.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { - val r = (angle / 180f * Math.PI).toFloat() - val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() + temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] + temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] + temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] + temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] + temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] + temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] + temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] + temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] + temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] + temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] + temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] + temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] + temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] + temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] + temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] + temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - matrix[0] = f / imageAspectRatio - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f + matrix[0] = temp[0] + matrix[1] = temp[1] + matrix[2] = temp[2] + matrix[3] = temp[3] + matrix[4] = temp[4] + matrix[5] = temp[5] + matrix[6] = temp[6] + matrix[7] = temp[7] + matrix[8] = temp[8] + matrix[9] = temp[9] + matrix[10] = temp[10] + matrix[11] = temp[11] + matrix[12] = temp[12] + matrix[13] = temp[13] + matrix[14] = temp[14] + matrix[15] = temp[15] + } - matrix[4] = 0.0f - matrix[5] = f - matrix[6] = 0.0f - matrix[7] = 0.0f + fun translate(x: Float, y: Float, z: Float) { + translateMatrix[12] = x + translateMatrix[13] = y + translateMatrix[14] = z - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = -(far + near) / (far - near) - matrix[11] = -1.0f + mul(translateMatrix) + } - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = -(2.0f * far * near) / (far - near) - matrix[15] = 0.0f - } + fun scale(x: Float, y: Float, z: Float) { + scaleMatrix[0] = x + scaleMatrix[5] = y + scaleMatrix[10] = z - fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { - matrix[0] = 2f / (right - left) - matrix[1] = 0f - matrix[2] = 0f - matrix[3] = 0f + mul(scaleMatrix) + } - matrix[4] = 0f - matrix[5] = 2f / (top - bottom) - matrix[6] = 0f - matrix[7] = 0f + fun rotateX(angle: Float) { + rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() + rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() + rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() + rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - matrix[8] = 0f - matrix[9] = 0f - matrix[10] = -2f / (far - near) - matrix[11] = 0f + mul(rotateXMatrix) + } - matrix[12] = - (right + left) / (right - left) - matrix[13] = - (top + bottom) / (top - bottom) - matrix[14] = - (far + near) / (far - near) - matrix[15] = 1f - } + fun rotateY(angle: Float) { + rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() + rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() + rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - fun setToIdentity() { - matrix[0] = 1.0f - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f - matrix[4] = 0.0f - matrix[5] = 1.0f - matrix[6] = 0.0f - matrix[7] = 0.0f - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = 1.0f - matrix[11] = 0.0f - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = 0.0f - matrix[15] = 1.0f - } + mul(rotateYMatrix) + } - fun mul(other: Matrix4) { - mul(other.get()) - } + fun rotateZ(angle: Float) { + rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() + rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() + rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - protected fun mul(other: FloatArray) { - if (other.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } - - temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] - temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] - temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] - temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] - temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] - temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] - temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] - temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] - temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] - temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] - temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] - temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] - temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] - temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] - temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] - temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - - matrix[0] = temp[0] - matrix[1] = temp[1] - matrix[2] = temp[2] - matrix[3] = temp[3] - matrix[4] = temp[4] - matrix[5] = temp[5] - matrix[6] = temp[6] - matrix[7] = temp[7] - matrix[8] = temp[8] - matrix[9] = temp[9] - matrix[10] = temp[10] - matrix[11] = temp[11] - matrix[12] = temp[12] - matrix[13] = temp[13] - matrix[14] = temp[14] - matrix[15] = temp[15] - } - - fun translate(x: Float, y: Float, z: Float) { - translateMatrix[12] = x - translateMatrix[13] = y - translateMatrix[14] = z - - mul(translateMatrix) - } - - fun scale(x: Float, y: Float, z: Float) { - scaleMatrix[0] = x - scaleMatrix[5] = y - scaleMatrix[10] = z - - mul(scaleMatrix) - } - - fun rotateX(angle: Float) { - rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() - rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() - rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() - rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateXMatrix) - } - - fun rotateY(angle: Float) { - rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() - rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() - rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateYMatrix) - } - - fun rotateZ(angle: Float) { - rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() - rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() - rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateZMatrix) - } + mul(rotateZMatrix) + } } diff --git a/src/main/kotlin/games/perses/net/NetUtils.kt b/src/main/kotlin/games/perses/net/NetUtils.kt index 5b5b820..148b920 100644 --- a/src/main/kotlin/games/perses/net/NetUtils.kt +++ b/src/main/kotlin/games/perses/net/NetUtils.kt @@ -9,10 +9,10 @@ */ fun getUrlAsString(url: String): String { - val req = XMLHttpRequest() + val req = XMLHttpRequest() - req.open("GET", url, false) - req.send(null) + req.open("GET", url, false) + req.send(null) - return req.responseText + return req.responseText } diff --git a/src/main/kotlin/games/perses/shader/ShaderProgram.kt b/src/main/kotlin/games/perses/shader/ShaderProgram.kt index cf07c0f..7dde03a 100644 --- a/src/main/kotlin/games/perses/shader/ShaderProgram.kt +++ b/src/main/kotlin/games/perses/shader/ShaderProgram.kt @@ -1,6 +1,10 @@ package games.perses.shader -import org.khronos.webgl.* +import org.khronos.webgl.Float32Array +import org.khronos.webgl.WebGLBuffer +import org.khronos.webgl.WebGLProgram +import org.khronos.webgl.WebGLRenderingContext +import org.khronos.webgl.WebGLShader /** * User: rnentjes @@ -9,103 +13,125 @@ */ class ShaderProgram( - val webgl: WebGLRenderingContext, - val drawType: Int, - vertexShaderSource: String, - fragmentShaderSource: String, - val vainfo: Array, - val setter: (program: ShaderProgram, data: T) -> Unit) { + val webgl: WebGLRenderingContext, + val drawType: Int, + vertexShaderSource: String, + fragmentShaderSource: String, + val vainfo: Array, + val setter: (program: ShaderProgram, data: T) -> Unit +) { - var shaderProgram: WebGLProgram - var vertex: WebGLShader - var fragment: WebGLShader + var shaderProgram: WebGLProgram + var vertex: WebGLShader + var fragment: WebGLShader - var verticesBlockSize = 0 - var drawLength = 0 + var verticesBlockSize = 0 + var drawLength = 0 - init { - vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER) - fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER) + init { + vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER) + fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER) - shaderProgram = webgl.createProgram() ?: throw IllegalStateException("Unable to request shader program from webgl context!") - webgl.attachShader(shaderProgram, vertex) - webgl.attachShader(shaderProgram, fragment) - webgl.linkProgram(shaderProgram) + shaderProgram = webgl.createProgram() ?: throw IllegalStateException( + "Unable to request shader program from webgl context!" + ) + webgl.attachShader(shaderProgram, vertex) + webgl.attachShader(shaderProgram, fragment) + webgl.linkProgram(shaderProgram) - if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) { - //println(webgl.getProgramInfoLog(shaderProgram)) - throw IllegalStateException("Unable to compile shader program!") - } - - webgl.useProgram(shaderProgram) - - this.verticesBlockSize = 0 - - // set attribute locations... - for (info in vainfo.iterator()) { - info.location = webgl.getAttribLocation(shaderProgram, info.locationName) - info.offset = verticesBlockSize - - verticesBlockSize += info.numElements - //println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}") - } - - when(drawType) { - WebGLRenderingContext.TRIANGLES -> { - drawLength = verticesBlockSize * 3 - } - else -> { - drawLength = verticesBlockSize - } - } - - //println("verticesBlockSize $verticesBlockSize") - - //println("ShaderProgram constructor done") + if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) { + //println(webgl.getProgramInfoLog(shaderProgram)) + throw IllegalStateException("Unable to compile shader program!") } - private fun compileShader(source: String, type: Int): WebGLShader { - val result: WebGLShader = webgl.createShader(type) ?: throw IllegalStateException("Unable to request shader from webgl context!") + webgl.useProgram(shaderProgram) - webgl.shaderSource(result, source) - webgl.compileShader(result) + this.verticesBlockSize = 0 - if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) { - throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}") - } + // set attribute locations... + for (info in vainfo.iterator()) { + info.location = webgl.getAttribLocation(shaderProgram, info.locationName) + info.offset = verticesBlockSize - return result + verticesBlockSize += info.numElements + //println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}") } - fun begin(attribBuffer: WebGLBuffer, userdata: T) { - webgl.useProgram(shaderProgram); - webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); - - // set attribute locations... - for (info in vainfo.iterator()) { - webgl.enableVertexAttribArray(info.location) - webgl.vertexAttribPointer(info.location, info.numElements, WebGLRenderingContext.FLOAT, false, verticesBlockSize * 4, info.offset * 4) - } - - setter(this, userdata) + when (drawType) { + WebGLRenderingContext.TRIANGLES -> { + drawLength = verticesBlockSize * 3 + } + else -> { + drawLength = verticesBlockSize + } } - fun end() { - for (info in vainfo.iterator()) { - webgl.disableVertexAttribArray(info.location); - } - webgl.useProgram(null) + //println("verticesBlockSize $verticesBlockSize") + + //println("ShaderProgram constructor done") + } + + private fun compileShader(source: String, type: Int): WebGLShader { + val result: WebGLShader = webgl.createShader(type) + ?: throw IllegalStateException("Unable to request shader from webgl context!") + + webgl.shaderSource(result, source) + webgl.compileShader(result) + + if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) { + throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}") } - fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location); + return result + } - fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location); + fun begin(attribBuffer: WebGLBuffer, userdata: T) { + webgl.useProgram(shaderProgram); + webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); - fun setUniform1f(location: String, value: Float) { webgl.uniform1f(getUniformLocation(location), value); } - fun setUniform2f(location: String, v1: Float, v2: Float) { webgl.uniform2f(getUniformLocation(location), v1, v2); } - fun setUniform3f(location: String, v1: Float, v2: Float, v3: Float) { webgl.uniform3f(getUniformLocation(location), v1, v2, v3); } - fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); } - fun setUniform1i(location: String, value: Int) { webgl.uniform1i(getUniformLocation(location), value); } - fun setUniformMatrix4fv(location: String, value: Float32Array) { webgl.uniformMatrix4fv(getUniformLocation(location), false, value); } + // set attribute locations... + for (info in vainfo.iterator()) { + webgl.enableVertexAttribArray(info.location) + webgl.vertexAttribPointer( + info.location, + info.numElements, + WebGLRenderingContext.FLOAT, + false, + verticesBlockSize * 4, + info.offset * 4 + ) + } + + setter(this, userdata) + } + + fun end() { + for (info in vainfo.iterator()) { + webgl.disableVertexAttribArray(info.location); + } + webgl.useProgram(null) + } + + fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location); + + fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location); + + fun setUniform1f(location: String, value: Float) { + webgl.uniform1f(getUniformLocation(location), value); } + + fun setUniform2f(location: String, v1: Float, v2: Float) { + webgl.uniform2f(getUniformLocation(location), v1, v2); } + + fun setUniform3f(location: String, v1: Float, v2: Float, v3: Float) { + webgl.uniform3f(getUniformLocation(location), v1, v2, v3); } + + fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { + webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); } + + fun setUniform1i(location: String, value: Int) { + webgl.uniform1i(getUniformLocation(location), value); } + + fun setUniformMatrix4fv(location: String, value: Float32Array) { + webgl.uniformMatrix4fv(getUniformLocation(location), false, value); } } diff --git a/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt b/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt index d9a3908..d65cf7f 100644 --- a/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt +++ b/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt @@ -11,64 +11,67 @@ * Time: 11:57 */ -class VertextAttributeInfo(val locationName: String, val numElements: Int) { - var location = 0 - var offset = 0 +class VertextAttributeInfo( + val locationName: String, + val numElements: Int +) { + var location = 0 + var offset = 0 } class ShaderProgramMesh( - val shaderProgram: ShaderProgram + val shaderProgram: ShaderProgram ) { - val webgl = shaderProgram.webgl - val data: Float32Array = Float32Array(20000 - (20000 % shaderProgram.drawLength)) - var currentIndex: Int = 0 - val attribBuffer: WebGLBuffer - var counter = 0 + val webgl = shaderProgram.webgl + val data: Float32Array = Float32Array(20000 - (20000 % shaderProgram.drawLength)) + var currentIndex: Int = 0 + val attribBuffer: WebGLBuffer + var counter = 0 - init { - attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!") - webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer) + init { + attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!") + webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer) + } + + fun queue(vararg vertices: Float) { + for (vertice in vertices) { + data[currentIndex++] = vertice } - fun queue(vararg vertices: Float) { - for (vertice in vertices) { - data[currentIndex++] = vertice - } - - if (bufferFull()) { - println("Skipped draw call, to many values!") - currentIndex = 0 - } + if (bufferFull()) { + println("Skipped draw call, to many values!") + currentIndex = 0 } + } - fun queueArray(vertices: Array) { - data.set(vertices, currentIndex) - currentIndex += vertices.size + fun queueArray(vertices: Array) { + data.set(vertices, currentIndex) + currentIndex += vertices.size - if (bufferFull()) { - println("Skipped draw call, to many values!") - currentIndex = 0 - } + if (bufferFull()) { + println("Skipped draw call, to many values!") + currentIndex = 0 } + } - fun remaining() = data.length - currentIndex + fun remaining() = data.length - currentIndex - fun bufferFull() = currentIndex == data.length + fun bufferFull() = currentIndex == data.length - fun render(userdata: T) { - counter++ - if (currentIndex > 0) { - if (currentIndex % shaderProgram.verticesBlockSize != 0) { - throw IllegalStateException("Number of vertices not a multiple of the attribute block size!") - } + fun render(userdata: T) { + counter++ + if (currentIndex > 0) { + if (currentIndex % shaderProgram.verticesBlockSize != 0) { + throw IllegalStateException("Number of vertices not a multiple of the attribute block size!") + } - shaderProgram.begin(attribBuffer, userdata) + shaderProgram.begin(attribBuffer, userdata) - webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW) - webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize)) - currentIndex = 0 + webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW) + webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize)) + currentIndex = 0 - shaderProgram.end() - } + shaderProgram.end() } + } } diff --git a/src/main/kotlin/games/perses/sound/Music.kt b/src/main/kotlin/games/perses/sound/Music.kt index a3fcccc..c5ddadf 100644 --- a/src/main/kotlin/games/perses/sound/Music.kt +++ b/src/main/kotlin/games/perses/sound/Music.kt @@ -10,43 +10,43 @@ */ fun HTMLAudioElement.dispose() { - this.pause() - this.parentNode?.removeChild(this) + this.pause() + this.parentNode?.removeChild(this) } object Music { - val playing: MutableSet = HashSet() + val playing: MutableSet = HashSet() - fun load(url: String): HTMLAudioElement { - val audio = document.createElement("audio") as HTMLAudioElement + fun load(url: String): HTMLAudioElement { + val audio = document.createElement("audio") as HTMLAudioElement - audio.src = url + audio.src = url - return audio - } + return audio + } - fun play(url: String, volume: Double = 0.75, looping: Boolean = false): HTMLAudioElement { - val audio = document.createElement("audio") as HTMLAudioElement + fun play(url: String, volume: Double = 0.75, looping: Boolean = false): HTMLAudioElement { + val audio = document.createElement("audio") as HTMLAudioElement - audio.src = url - audio.volume = volume + audio.src = url + audio.volume = volume + audio.play() + + audio.onended = { + if (looping) { + audio.currentTime = 0.0 audio.play() - - audio.onended = { - if (looping) { - audio.currentTime = 0.0 - audio.play() - } else { - //println("REMOVING: $audio") - audio.parentNode?.removeChild(audio) - playing.remove(audio) - } - } - - return audio + } else { + //println("REMOVING: $audio") + audio.parentNode?.removeChild(audio) + playing.remove(audio) + } } - fun stopAll() { + return audio + } - } + fun stopAll() { + + } } diff --git a/src/main/kotlin/games/perses/sound/Sounds.kt b/src/main/kotlin/games/perses/sound/Sounds.kt index f866817..f00aa06 100644 --- a/src/main/kotlin/games/perses/sound/Sounds.kt +++ b/src/main/kotlin/games/perses/sound/Sounds.kt @@ -9,83 +9,88 @@ * Time: 12:34 */ -class Sound(val name:String, val url: String, val defaultVolume: Double = 0.75, val numberOfChannels: Int) { - var channels: Array = +class Sound( + val name: String, + val url: String, + val defaultVolume: Double = 0.75, + val numberOfChannels: Int +) { + var channels: Array = Array(numberOfChannels, { document.createElement("audio") as HTMLAudioElement }) - var nextChannel: Int = 0 + var nextChannel: Int = 0 - init { - //println("CREATING: $name") + init { + //println("CREATING: $name") - for (audio in channels) { - if (audio != null) { - audio.src = url - audio.pause() - audio.load() - audio.volume = defaultVolume - } - } + for (audio in channels) { + if (audio != null) { + audio.src = url + audio.pause() + audio.load() + audio.volume = defaultVolume + } } + } - fun play(volume: Double = defaultVolume) { - //println("PLAYING: $name - $nextChannel") - channels[nextChannel]?.volume = volume - channels[nextChannel]?.currentTime = 0.0 - channels[nextChannel]?.play() + fun play(volume: Double = defaultVolume) { + //println("PLAYING: $name - $nextChannel") + channels[nextChannel]?.volume = volume + channels[nextChannel]?.currentTime = 0.0 + channels[nextChannel]?.play() - nextChannel = (nextChannel + 1) % channels.size + nextChannel = (nextChannel + 1) % channels.size + } + + fun pause() { + for (audio in channels) { + audio?.pause() } + } - fun pause() { - for (audio in channels) { - audio?.pause() - } + fun dispose() { + for (audio in channels) { + audio?.dispose() } - - fun dispose() { - for (audio in channels) { - audio?.dispose() - } - } + } } object Sounds { - val sounds: MutableMap = HashMap() + val sounds: MutableMap = HashMap() - fun load(name: String, url: String, volume: Double = 0.75, channels: Int = 1 ) { - sounds.put(name, Sound(name, url, volume, channels)) + fun load(name: String, url: String, volume: Double = 0.75, channels: Int = 1) { + sounds.put(name, Sound(name, url, volume, channels)) + } + + fun play(name: String, volume: Double? = null) { + val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!") + + if (volume != null) { + sound.play(volume) + } else { + sound.play() + } + } + + fun pause(name: String) { + val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!") + + sound.pause() + } + + fun dispose(name: String) { + val sound: Sound? = sounds[name] + + if (sound != null) { + sounds.remove(name) + sound.dispose() + } + } + + fun disposeAll() { + for (sound in sounds.values) { + sound.dispose() } - fun play(name: String, volume: Double? = null) { - val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!") - - if (volume != null) { - sound.play(volume) - } else { - sound.play() - } - } - - fun pause(name: String) { - val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!") - - sound.pause() - } - - fun dispose(name: String) { - val sound: Sound? = sounds[name] - - if (sound != null) { - sounds.remove(name) - sound.dispose() - } - } - - fun disposeAll() { - for (sound in sounds.values) { - sound.dispose() - } - - sounds.clear() - } + sounds.clear() + } } diff --git a/src/main/kotlin/games/perses/sprite/SpriteBatch.kt b/src/main/kotlin/games/perses/sprite/SpriteBatch.kt index 3de1163..f0b4557 100644 --- a/src/main/kotlin/games/perses/sprite/SpriteBatch.kt +++ b/src/main/kotlin/games/perses/sprite/SpriteBatch.kt @@ -10,17 +10,17 @@ */ class Sprite(val textureName: String) { - val texture: Texture by lazy { Textures.get(textureName) } + val texture: Texture by lazy { Textures[textureName] } } class SpriteBatch { - fun draw(sprite: Sprite, x: Float, y: Float, scale: Float = 1f, rotation: Float = 0f) { - sprite.texture.queueDraw(x, y, scale, rotation) - } + fun draw(sprite: Sprite, x: Float, y: Float, scale: Float = 1f, rotation: Float = 0f) { + sprite.texture.queueDraw(x, y, scale, rotation) + } - fun render() { - Textures.render() - } + fun render() { + Textures.render() + } } diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml index 43edcc2..7ed1494 100644 --- a/.idea/modules/kudens_test.iml +++ b/.idea/modules/kudens_test.iml @@ -1,8 +1,9 @@ - + + $MODULE_DIR$/../../build/kotlinjs/kudens.js \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7ae9969..e7225a0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'perses.games' -version '1.1.6-SNAPSHOT' +version '1.1.7-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'idea' @@ -20,7 +20,7 @@ } buildscript { - ext.kotlin_version = '1.2.21' + ext.kotlin_version = '1.2.30' repositories { maven { url "http://nexus.astraeus.nl/nexus/content/groups/public" diff --git a/src/main/kotlin/games/perses/color/Color.kt b/src/main/kotlin/games/perses/color/Color.kt index 7f235b0..31b540f 100644 --- a/src/main/kotlin/games/perses/color/Color.kt +++ b/src/main/kotlin/games/perses/color/Color.kt @@ -10,107 +10,107 @@ object Color { - /** - * Converts an HSL color value to RGB. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes h, s, and l are contained in the set [0, 1] and - * returns r, g, and b in the set [0, 255]. + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. - * @param h The hue - * * - * @param s The saturation - * * - * @param l The lightness - * * - * @return int array, the RGB representation - */ - fun hslToRgb(h: Float, s: Float, l: Float): IntArray { - val r: Float - val g: Float - val b: Float + * @param h The hue + * * + * @param s The saturation + * * + * @param l The lightness + * * + * @return int array, the RGB representation + */ + fun hslToRgb(h: Float, s: Float, l: Float): IntArray { + val r: Float + val g: Float + val b: Float - if (s == 0f) { - b = l - g = b - r = g // achromatic - } else { - val q = if (l < 0.5f) l * (1 + s) else l + s - l * s - val p = 2 * l - q - r = hueToRgb(p, q, h + 1f / 3f) - g = hueToRgb(p, q, h) - b = hueToRgb(p, q, h - 1f / 3f) - } - val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) + if (s == 0f) { + b = l + g = b + r = g // achromatic + } else { + val q = if (l < 0.5f) l * (1 + s) else l + s - l * s + val p = 2 * l - q + r = hueToRgb(p, q, h + 1f / 3f) + g = hueToRgb(p, q, h) + b = hueToRgb(p, q, h - 1f / 3f) + } + val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) - return rgb + return rgb + } + + /** Helper method that converts hue to rgb */ + fun hueToRgb(p: Float, q: Float, t: Float): Float { + var lt = t + if (lt < 0f) { + lt += 1f + } + if (lt > 1f) { + lt -= 1f + } + if (lt < 1f / 6f) { + return p + (q - p) * 6f * lt + } + if (lt < 1f / 2f) { + return q + } + if (lt < 2f / 3f) { + return p + (q - p) * (2f / 3f - lt) * 6f + } + return p + } + + /** + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes pR, pG, and bpBare contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + + * @param pR The red color value + * * + * @param pG The green color value + * * + * @param pB The blue color value + * * + * @return float array, the HSL representation + */ + fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { + val r = pR / 255f + val g = pG / 255f + val b = pB / 255f + + val max = if (r > g && r > b) r else if (g > b) g else b + val min = if (r < g && r < b) r else if (g < b) g else b + + var h: Float + val s: Float + val l: Float + l = (max + min) / 2.0f + + if (max == min) { + s = 0.0f + h = s + } else { + val d = max - min + s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) + + if (r > g && r > b) + h = (g - b) / d + (if (g < b) 6.0f else 0.0f) + else if (g > b) + h = (b - r) / d + 2.0f + else + h = (r - g) / d + 4.0f + + h /= 6.0f } - /** Helper method that converts hue to rgb */ - fun hueToRgb(p: Float, q: Float, t: Float): Float { - var lt = t - if (lt < 0f) { - lt += 1f - } - if (lt > 1f) { - lt -= 1f - } - if (lt < 1f / 6f) { - return p + (q - p) * 6f * lt - } - if (lt < 1f / 2f) { - return q - } - if (lt < 2f / 3f) { - return p + (q - p) * (2f / 3f - lt) * 6f - } - return p - } - - /** - * Converts an RGB color value to HSL. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes pR, pG, and bpBare contained in the set [0, 255] and - * returns h, s, and l in the set [0, 1]. - - * @param pR The red color value - * * - * @param pG The green color value - * * - * @param pB The blue color value - * * - * @return float array, the HSL representation - */ - fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { - val r = pR / 255f - val g = pG / 255f - val b = pB / 255f - - val max = if (r > g && r > b) r else if (g > b) g else b - val min = if (r < g && r < b) r else if (g < b) g else b - - var h: Float - val s: Float - val l: Float - l = (max + min) / 2.0f - - if (max == min) { - s = 0.0f - h = s - } else { - val d = max - min - s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) - - if (r > g && r > b) - h = (g - b) / d + (if (g < b) 6.0f else 0.0f) - else if (g > b) - h = (b - r) / d + 2.0f - else - h = (r - g) / d + 4.0f - - h /= 6.0f - } - - val hsl = floatArrayOf(h, s, l) - return hsl - } + val hsl = floatArrayOf(h, s, l) + return hsl + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/game/Game.kt b/src/main/kotlin/games/perses/game/Game.kt index 0961316..1becee5 100644 --- a/src/main/kotlin/games/perses/game/Game.kt +++ b/src/main/kotlin/games/perses/game/Game.kt @@ -14,210 +14,210 @@ */ enum class DrawMode { - LINEAR, - NEAREST + LINEAR, + NEAREST } class HTMLElements { - var container: HTMLElement - var webgl: WebGLRenderingContext - var canvas2d: CanvasRenderingContext2D + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D - init { - container = document.createElement("div") as HTMLElement + init { + container = document.createElement("div") as HTMLElement - val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement - val canvas = document.createElement("canvas") as HTMLCanvasElement + val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + val canvas = document.createElement("canvas") as HTMLCanvasElement - container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") - webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" ) - canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" ) + container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;") - document.body!!.appendChild(container) - container.appendChild(webGlCanvas) - container.appendChild(canvas) + document.body!!.appendChild(container) + container.appendChild(webGlCanvas) + container.appendChild(canvas) - val canvas2dcanvas = canvas.getContext("2d") + val canvas2dcanvas = canvas.getContext("2d") - var webglcanvas = webGlCanvas.getContext("webgl") - if (webglcanvas == null) { - console.log("webgl context not found, trying experimental-webgl.") - webglcanvas = webGlCanvas.getContext("experimental-webgl") - } - - if (webglcanvas != null) { - webgl = webglcanvas as WebGLRenderingContext - } else { - console.log("webgl?", webglcanvas) - window.alert("Your browser doesn't seem to support webgl!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } - - if (canvas2dcanvas != null) { - canvas2d = canvas2dcanvas as CanvasRenderingContext2D - } else { - console.log("canvas2d?", canvas2dcanvas) - window.alert("Your browser doesn't seem to support 2d canvas!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } + var webglcanvas = webGlCanvas.getContext("webgl") + if (webglcanvas == null) { + console.log("webgl context not found, trying experimental-webgl.") + webglcanvas = webGlCanvas.getContext("experimental-webgl") } + + if (webglcanvas != null) { + webgl = webglcanvas as WebGLRenderingContext + } else { + console.log("webgl?", webglcanvas) + window.alert("Your browser doesn't seem to support webgl!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + + if (canvas2dcanvas != null) { + canvas2d = canvas2dcanvas as CanvasRenderingContext2D + } else { + console.log("canvas2d?", canvas2dcanvas) + window.alert("Your browser doesn't seem to support 2d canvas!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + } } object Game { - var started = false - val view: View = View() - val html: HTMLElements by lazy { HTMLElements() } - var currentScreen: Screen = DefaultScreen() - var start = Date().getTime() - var currentTime = start - var currentDelta = 0f - var pause: Boolean = false - var clearScreenEveryFrame = true + var started = false + val view: View = View() + val html: HTMLElements by lazy { HTMLElements() } + var currentScreen: Screen = DefaultScreen() + var start = Date().getTime() + var currentTime = start + var currentDelta = 0f + var pause: Boolean = false + var clearScreenEveryFrame = true - var clearRed = 0f - var clearGreen = 0f - var clearBlue = 0f - var clearAlpha = 1f + var clearRed = 0f + var clearGreen = 0f + var clearBlue = 0f + var clearAlpha = 1f - var fps = 0 - var fpsCount = 0 - var fpsCountTime = 0f + var fps = 0 + var fpsCount = 0 + var fpsCountTime = 0f - var borderLeft = 0 - var borderTop = 0 + var borderLeft = 0 + var borderTop = 0 - var focus = true + var focus = true - init { - window.onfocus = { - //println("GOT FOCUS!") + init { + window.onfocus = { + //println("GOT FOCUS!") - focus = true - "" - } - window.onblur = { - //println("LOST FOCUS!") + focus = true + "" + } + window.onblur = { + //println("LOST FOCUS!") - focus = false - "" - } - + focus = false + "" } - fun gl() = html.webgl + } - fun resize() { - val canvas = gl().canvas + fun gl() = html.webgl - // Check if the canvas is not the same size. - val windowWidth = window.innerWidth.toInt() - val windowHeight = window.innerHeight.toInt() + fun resize() { + val canvas = gl().canvas - if (view.lastWindowWidth != windowWidth || - view.lastWindowHeight != windowHeight) { - view.lastWindowWidth = windowWidth - view.lastWindowHeight = windowHeight - view.windowWidth = windowWidth - view.windowHeight = windowHeight + // Check if the canvas is not the same size. + val windowWidth = window.innerWidth.toInt() + val windowHeight = window.innerHeight.toInt() - view.updateView() + if (view.lastWindowWidth != windowWidth || + view.lastWindowHeight != windowHeight) { + view.lastWindowWidth = windowWidth + view.lastWindowHeight = windowHeight + view.windowWidth = windowWidth + view.windowHeight = windowHeight - val textCanvas = html.canvas2d.canvas + view.updateView() - // Make the canvas the same size - canvas.width = view.width.toInt() - canvas.height = view.height.toInt() + val textCanvas = html.canvas2d.canvas - textCanvas.width = view.width.toInt() - textCanvas.height = view.height.toInt() + // Make the canvas the same size + canvas.width = view.width.toInt() + canvas.height = view.height.toInt() - gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) + textCanvas.width = view.width.toInt() + textCanvas.height = view.height.toInt() - borderLeft = (windowWidth - view.windowWidth) / 2 - borderTop = (windowHeight - view.windowHeight) / 2 + gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) - canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) - textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) + borderLeft = (windowWidth - view.windowWidth) / 2 + borderTop = (windowHeight - view.windowHeight) / 2 + + canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + } + } + + fun start(startScreen: Screen) { + if (started) { + throw IllegalStateException("You can only start a game once!") + } + + setScreen(startScreen) + + // start game loop + started = true + gameLoop() + } + + fun setScreen(screen: Screen) { + currentScreen.unloadResources() + + currentScreen = screen + + screen.loadResources() + } + + fun setClearColor(r: Float, g: Float, b: Float, a: Float) { + clearRed = r + clearGreen = g + clearBlue = b + clearAlpha = a + } + + fun gameLoop() { + try { + if (!Textures.ready()) { + gl().clearColor(1f, 1f, 1f, 1f) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } else { + resize() + + if (!pause) { + html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); + + if (clearScreenEveryFrame) { + gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } + + gl().enable(WebGLRenderingContext.BLEND) + gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); + + val time = Date().getTime() + currentDelta = ((time - currentTime) / 1000f).toFloat() + currentTime = time + + val timeInSeconds = (currentTime - start) / 1000f + + fpsCountTime += currentDelta + fpsCount++ + while (fpsCountTime > 1f) { + fps = fpsCount + fpsCountTime -= 1f + fpsCount = 0 + } + + if (focus) { + currentScreen.update(timeInSeconds.toFloat(), currentDelta) + } + + currentScreen.render() } + } + } catch (e: Exception) { + println("Some error...") + console.log(e) } - fun start(startScreen: Screen) { - if (started) { - throw IllegalStateException("You can only start a game once!") - } - - setScreen(startScreen) - - // start game loop - started = true - gameLoop() + window.requestAnimationFrame { + gameLoop() } - - fun setScreen(screen: Screen) { - currentScreen.unloadResources() - - currentScreen = screen - - screen.loadResources() - } - - fun setClearColor(r: Float, g: Float, b: Float, a: Float) { - clearRed = r - clearGreen = g - clearBlue = b - clearAlpha = a - } - - fun gameLoop() { - try { - if (!Textures.ready()) { - gl().clearColor(1f, 1f, 1f, 1f) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } else { - resize() - - if (!pause) { - html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); - - if (clearScreenEveryFrame) { - gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } - - gl().enable(WebGLRenderingContext.BLEND) - gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); - - val time = Date().getTime() - currentDelta = ((time - currentTime) / 1000f).toFloat() - currentTime = time - - val timeInSeconds = (currentTime - start) / 1000f - - fpsCountTime += currentDelta - fpsCount++ - while (fpsCountTime > 1f) { - fps = fpsCount - fpsCountTime -= 1f - fpsCount = 0 - } - - if (focus) { - currentScreen.update(timeInSeconds.toFloat(), currentDelta) - } - - currentScreen.render() - } - } - } catch(e: Exception) { - println("Some error...") - console.log(e) - } - - window.requestAnimationFrame { - gameLoop() - } - } + } } diff --git a/src/main/kotlin/games/perses/game/Screen.kt b/src/main/kotlin/games/perses/game/Screen.kt index 10b6eae..7b381e7 100644 --- a/src/main/kotlin/games/perses/game/Screen.kt +++ b/src/main/kotlin/games/perses/game/Screen.kt @@ -8,31 +8,31 @@ abstract class Screen { - open fun loadResources() {} + open fun loadResources() {} - @Deprecated( + @Deprecated( message = "replace with unloadResources", replaceWith = ReplaceWith("unloadResources()") - ) - open fun closeResources() { - unloadResources() - } + ) + open fun closeResources() { + unloadResources() + } - open fun unloadResources() {} + open fun unloadResources() {} - abstract fun update(time: Float, delta: Float) + abstract fun update(time: Float, delta: Float) - abstract fun render() + abstract fun render() } -class DefaultScreen: Screen() { - override fun update(time: Float, delta: Float) { - } +class DefaultScreen : Screen() { + override fun update(time: Float, delta: Float) { + } - override fun render() { - // show loading message? - Game.gl().clearColor(1f, 1f, 0f, 1f) - Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } + override fun render() { + // show loading message? + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } } diff --git a/src/main/kotlin/games/perses/game/View.kt b/src/main/kotlin/games/perses/game/View.kt index 540a44d..16c9913 100644 --- a/src/main/kotlin/games/perses/game/View.kt +++ b/src/main/kotlin/games/perses/game/View.kt @@ -4,39 +4,39 @@ import kotlin.browser.document enum class ViewType { - PROJECTION, - WIDTH, - HEIGHT, - ABSOLUTE + PROJECTION, + WIDTH, + HEIGHT, + ABSOLUTE } class View( - var lastWindowWidth: Int = 2000, - var lastWindowHeight: Int = 1000, - var windowWidth: Int = 2000, - var windowHeight: Int = 1000, - var width: Float = 1024f, - var height: Float = 1024f, - var angle: Float = 60f, - var near: Float = -0.1f, - var far: Float = -100f, - var minAspectRatio: Float = 1f, - var maxAspectRatio: Float = 1f, - var leftOffset: Int = 0, - var bottomOffset: Int = 0, - var viewType: ViewType = ViewType.WIDTH, - var drawMode: DrawMode = DrawMode.LINEAR) { - var vMatrix = Matrix4() - var aspectRatio = 1f + var lastWindowWidth: Int = 2000, + var lastWindowHeight: Int = 1000, + var windowWidth: Int = 2000, + var windowHeight: Int = 1000, + var width: Float = 1024f, + var height: Float = 1024f, + var angle: Float = 60f, + var near: Float = -0.1f, + var far: Float = -100f, + var minAspectRatio: Float = 1f, + var maxAspectRatio: Float = 1f, + var leftOffset: Int = 0, + var bottomOffset: Int = 0, + var viewType: ViewType = ViewType.WIDTH, + var drawMode: DrawMode = DrawMode.LINEAR) { + var vMatrix = Matrix4() + var aspectRatio = 1f - init { - updateView() - } + init { + updateView() + } - fun requestFullscreen() { - val element = document.body - //language=javascript - js(""" + fun requestFullscreen() { + val element = document.body + //language=javascript + js(""" if(element.requestFullscreen) { element.requestFullscreen(); } else if(element.mozRequestFullScreen) { @@ -47,10 +47,10 @@ element.msRequestFullscreen(); } """) - } + } - fun exitFullscreen() { - js(""" + fun exitFullscreen() { + js(""" if(document.exitFullscreen) { document.exitFullscreen(); } else if(document.mozCancelFullScreen) { @@ -59,178 +59,178 @@ document.webkitExitFullscreen(); } """) + } + + fun switchFullscreen() { + if (isFullscreen()) { + exitFullscreen() + } else { + requestFullscreen() + } + } + + fun isFullscreen(): Boolean { + val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + + return fse != undefined + } + + fun updateView() { + aspectRatio = windowWidth / windowHeight.toFloat() + + if (aspectRatio < minAspectRatio) { + aspectRatio = minAspectRatio + + windowHeight = (windowWidth / aspectRatio).toInt() } - fun switchFullscreen() { - if (isFullscreen()) { - exitFullscreen() - } else { - requestFullscreen() - } + if (aspectRatio > maxAspectRatio) { + aspectRatio = maxAspectRatio + + windowWidth = (windowHeight * aspectRatio).toInt() } - fun isFullscreen(): Boolean { - val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + when (viewType) { + ViewType.ABSOLUTE -> { + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.WIDTH -> { + height = width / aspectRatio - return fse != undefined + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.HEIGHT -> { + width = height * aspectRatio + + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.PROJECTION -> { + vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun updateView() { - aspectRatio = windowWidth / windowHeight.toFloat() + //println("width: $width, height: $height") + } - if (aspectRatio < minAspectRatio) { - aspectRatio = minAspectRatio + fun screenToGameCoordX(screenX: Float): Float { + var result = screenX - windowHeight = (windowWidth / aspectRatio).toInt() - } - - if (aspectRatio > maxAspectRatio) { - aspectRatio = maxAspectRatio - - windowWidth = (windowHeight * aspectRatio).toInt() - } - - when (viewType) { - ViewType.ABSOLUTE -> { - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.WIDTH -> { - height = width / aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.HEIGHT -> { - width = height * aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.PROJECTION -> { - vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } - - //println("width: $width, height: $height") + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = ((screenX - Game.borderLeft) * width / windowWidth) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordX(screenX: Float): Float { - var result = screenX + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( (screenX - Game.borderLeft) * width / windowWidth ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun screenToGameCoordY(screenY: Float): Float { + var result = screenY - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - ((screenY - Game.borderTop) * height / windowHeight) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordY(screenY: Float): Float { - var result = screenY + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( (screenY - Game.borderTop) * height / windowHeight ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordX(gameX: Float): Float { + var result = gameX + val normalizedX = gameX + (width / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = (gameX / width * windowWidth) + Game.borderLeft + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordX(gameX: Float): Float { - var result = gameX - val normalizedX = gameX + (width / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( gameX / width * windowWidth ) + Game.borderLeft - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordY(gameY: Float): Float { + var result = gameY + val normalizedY = gameY + (height / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - (gameY / height * windowHeight) + Game.borderTop + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordY(gameY: Float): Float { - var result = gameY - val normalizedY = gameY + (height / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( gameY / height * windowHeight ) + Game.borderTop - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun setToWidth(width: Float) { + this.width = width + this.viewType = ViewType.WIDTH - return result - } + updateView() + } - fun setToWidth(width: Float) { - this.width = width - this.viewType = ViewType.WIDTH + fun setToHeight(height: Float) { + this.height = height + this.viewType = ViewType.HEIGHT - updateView() - } + updateView() + } - fun setToHeight(height: Float) { - this.height = height - this.viewType = ViewType.HEIGHT + fun setProjection(angle: Float) { + this.angle = angle + this.viewType = ViewType.PROJECTION - updateView() - } + updateView() + } - fun setProjection(angle: Float) { - this.angle = angle - this.viewType = ViewType.PROJECTION + fun setNear(near: Float) { + this.near = near - updateView() - } + updateView() + } - fun setNear(near: Float) { - this.near = near + fun setFar(far: Float) { + this.far = far - updateView() - } - - fun setFar(far: Float) { - this.far = far - - updateView() - } + updateView() + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/input/Input.kt b/src/main/kotlin/games/perses/input/Input.kt index 71a3adc..58c4f23 100644 --- a/src/main/kotlin/games/perses/input/Input.kt +++ b/src/main/kotlin/games/perses/input/Input.kt @@ -15,235 +15,235 @@ */ enum class KeyCode(val keyCode: Int) { - BACKSPACE(8), - TAB(9), - ENTER(13), - SHIFT(16), - CTRL(17), - ALT(18), - PAUSE_BREAK(19), - CAPS_LOCK(20), - ESCAPE(27), - SPACE(32), - PAGE_UP(33), - PAGE_DOWN(34), - END(35), - HOME(36), - LEFT_ARROW(37), - UP_ARROW(38), - RIGHT_ARROW(39), - DOWN_ARROW(40), - INSERT(45), - DELETE(46), - NR_0(48), - NR_1(49), - NR_2(50), - NR_3(51), - NR_4(52), - NR_5(53), - NR_6(54), - NR_7(55), - NR_8(56), - NR_9(57), - A(65), - B(66), - C(67), - D(68), - E(69), - F(70), - G(71), - H(72), - I(73), - J(74), - K(75), - L(76), - M(77), - N(78), - O(79), - P(80), - Q(81), - R(82), - S(83), - T(84), - U(85), - V(86), - W(87), - X(88), - Y(89), - Z(90), - LEFT_WINDOW_KEY(91), - RIGHT_WINDOW_KEY(92), - SELECT_KEY(93), - NUMPAD_0(96), - NUMPAD_1(97), - NUMPAD_2(98), - NUMPAD_3(99), - NUMPAD_4(100), - NUMPAD_5(101), - NUMPAD_6(102), - NUMPAD_7(103), - NUMPAD_8(104), - NUMPAD_9(105), - MULTIPLY(106), - ADD(107), - SUBTRACT(109), - DECIMAL_POINT(110), - DIVIDE(111), - F1(112), - F2(113), - F3(114), - F4(115), - F5(116), - F6(117), - F7(118), - F8(119), - F9(120), - F10(121), - F11(122), - F12(123), - NUM_LOCK(144), - SCROLL_LOCK(145), - SEMI_COLON(186), - EQUAL_SIGN(187), - COMMA(188), - DASH(189), - PERIOD(190), - FORWARD_SLASH(191), - GRAVE_ACCENT(192), - OPEN_BRACKET(219), - BACK_SLASH(220), - CLOSE_BRAKET(221), - SINGLE_QUOTE(222), + BACKSPACE(8), + TAB(9), + ENTER(13), + SHIFT(16), + CTRL(17), + ALT(18), + PAUSE_BREAK(19), + CAPS_LOCK(20), + ESCAPE(27), + SPACE(32), + PAGE_UP(33), + PAGE_DOWN(34), + END(35), + HOME(36), + LEFT_ARROW(37), + UP_ARROW(38), + RIGHT_ARROW(39), + DOWN_ARROW(40), + INSERT(45), + DELETE(46), + NR_0(48), + NR_1(49), + NR_2(50), + NR_3(51), + NR_4(52), + NR_5(53), + NR_6(54), + NR_7(55), + NR_8(56), + NR_9(57), + A(65), + B(66), + C(67), + D(68), + E(69), + F(70), + G(71), + H(72), + I(73), + J(74), + K(75), + L(76), + M(77), + N(78), + O(79), + P(80), + Q(81), + R(82), + S(83), + T(84), + U(85), + V(86), + W(87), + X(88), + Y(89), + Z(90), + LEFT_WINDOW_KEY(91), + RIGHT_WINDOW_KEY(92), + SELECT_KEY(93), + NUMPAD_0(96), + NUMPAD_1(97), + NUMPAD_2(98), + NUMPAD_3(99), + NUMPAD_4(100), + NUMPAD_5(101), + NUMPAD_6(102), + NUMPAD_7(103), + NUMPAD_8(104), + NUMPAD_9(105), + MULTIPLY(106), + ADD(107), + SUBTRACT(109), + DECIMAL_POINT(110), + DIVIDE(111), + F1(112), + F2(113), + F3(114), + F4(115), + F5(116), + F6(117), + F7(118), + F8(119), + F9(120), + F10(121), + F11(122), + F12(123), + NUM_LOCK(144), + SCROLL_LOCK(145), + SEMI_COLON(186), + EQUAL_SIGN(187), + COMMA(188), + DASH(189), + PERIOD(190), + FORWARD_SLASH(191), + GRAVE_ACCENT(192), + OPEN_BRACKET(219), + BACK_SLASH(220), + CLOSE_BRAKET(221), + SINGLE_QUOTE(222), - ESC(27), - LEFT(37), - UP(38), - DOWN(40), - RIGHT(39), - MINUS(109), - PLUS(107), + ESC(27), + LEFT(37), + UP(38), + DOWN(40), + RIGHT(39), + MINUS(109), + PLUS(107), } interface InputProcessor { - fun keyPressed(charCode: Int) + fun keyPressed(charCode: Int) - fun keyDown(keyCode: Int) + fun keyDown(keyCode: Int) - fun keyUp(keyCode: Int) + fun keyUp(keyCode: Int) - fun pointerClick(pointer: Int, x: Float, y: Float) + fun pointerClick(pointer: Int, x: Float, y: Float) - fun mouseMove(x: Float, y: Float) + fun mouseMove(x: Float, y: Float) } open class EmptyInputProcessor : InputProcessor { - override fun pointerClick(pointer: Int, x: Float, y: Float) { } + override fun pointerClick(pointer: Int, x: Float, y: Float) {} - override fun keyDown(keyCode: Int) { } + override fun keyDown(keyCode: Int) {} - override fun keyPressed(charCode: Int) { } + override fun keyPressed(charCode: Int) {} - override fun keyUp(keyCode: Int) { } + override fun keyUp(keyCode: Int) {} - override fun mouseMove(x: Float, y: Float) { } + override fun mouseMove(x: Float, y: Float) {} } object Input { - private val keys: MutableMap = HashMap() - private var inputProcesser: InputProcessor = EmptyInputProcessor() + private val keys: MutableMap = HashMap() + private var inputProcesser: InputProcessor = EmptyInputProcessor() - init { - val body = document.body - if (body != null) { - body.onkeydown = { - keyDown(it) - } + init { + val body = document.body + if (body != null) { + body.onkeydown = { + keyDown(it) + } - body.onkeyup = { - keyUp(it) - } + body.onkeyup = { + keyUp(it) + } - body.onkeypress = { - keyPress(it) - } + body.onkeypress = { + keyPress(it) + } - body.onclick = { - mouseClick(it) - } + body.onclick = { + mouseClick(it) + } - body.onmousedown = { - mouseMove(it) - } + body.onmousedown = { + mouseMove(it) + } - body.onmouseup = { - mouseMove(it) - } + body.onmouseup = { + mouseMove(it) + } - body.onmousemove = { - mouseMove(it) - } - } else { - console.log("Can't register key events, document.body is null!?") - } + body.onmousemove = { + mouseMove(it) + } + } else { + console.log("Can't register key events, document.body is null!?") } + } - fun setInputProcessor(processor: InputProcessor) { - this.inputProcesser = processor + fun setInputProcessor(processor: InputProcessor) { + this.inputProcesser = processor + } + + private fun keyDown(key: Event) { + if (key is KeyboardEvent) { + keys.put(key.keyCode, Date().getTime()) + + inputProcesser.keyDown(key.keyCode) } + } - private fun keyDown(key: Event) { - if (key is KeyboardEvent) { - keys.put(key.keyCode, Date().getTime()) + private fun keyUp(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyUp(key.keyCode) - inputProcesser.keyDown(key.keyCode) - } + keys.remove(key.keyCode) } + } - private fun keyUp(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyUp(key.keyCode) - - keys.remove(key.keyCode) - } + private fun keyPress(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyPressed(key.charCode) } + } - private fun keyPress(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyPressed(key.charCode) - } + private fun mouseClick(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + + inputProcesser.pointerClick(event.button.toInt(), vx, vy) } + } - private fun mouseClick(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + private fun mouseMove(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) - inputProcesser.pointerClick(event.button.toInt(), vx, vy) - } + inputProcesser.mouseMove(vx, vy) } + } - private fun mouseMove(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + fun isDown(keyCode: Int) = keys.containsKey(keyCode) - inputProcesser.mouseMove(vx, vy) - } - } + fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - fun isDown(keyCode: Int) = keys.containsKey(keyCode) + fun wasPressed(keyCode: Int, delta: Double): Boolean { + val time = keys[keyCode] - fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - - fun wasPressed(keyCode: Int, delta: Double): Boolean { - val time = keys[keyCode] - - return (time != null && time > (Date().getTime() - delta)) - } + return (time != null && time > (Date().getTime() - delta)) + } } diff --git a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt index f1c7808..f3d4126 100644 --- a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt +++ b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt @@ -11,201 +11,201 @@ */ class MapData { - var version: Int = 1 - var properties: MutableMap = HashMap() - var layers: Array? = null - var tilesets: Array? = null + var version: Int = 1 + var properties: MutableMap = HashMap() + var layers: Array? = null + var tilesets: Array? = null - var height: Int = 0 - var width: Int = 0 + var height: Int = 0 + var width: Int = 0 - var nextobjectid: Int = 0 - var orientation: String = "orthogonal" - var renderorder: String = "right-down" - var tileheight: Int = 0 - var tilewidth: Int = 0 + var nextobjectid: Int = 0 + var orientation: String = "orthogonal" + var renderorder: String = "right-down" + var tileheight: Int = 0 + var tilewidth: Int = 0 } class MapLayer { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var data: Array? = null - var encoding: String = "" - var x: Int = 0 - var y: Int = 0 - var width: Int = 0 - var height: Int = 0 - var name: String = "" - var opacity: Float = 1f - var type: String = "" - var visible: Boolean = true - var draworder: String = "" + var data: Array? = null + var encoding: String = "" + var x: Int = 0 + var y: Int = 0 + var width: Int = 0 + var height: Int = 0 + var name: String = "" + var opacity: Float = 1f + var type: String = "" + var visible: Boolean = true + var draworder: String = "" } class MapTileset { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var firstgid: Int = 0 - var image: String = "" - var imageheight: Int = 0 - var imagewidth: Int = 0 - var margin: Int = 0 - var name: String = "" - var spacing: Int = 0 - var tilecount: Int = 0 - var tileheight: Int = 0 - var tilewidth: Int = 0 - var tileproperties: MutableMap> = HashMap() + var firstgid: Int = 0 + var image: String = "" + var imageheight: Int = 0 + var imagewidth: Int = 0 + var margin: Int = 0 + var name: String = "" + var spacing: Int = 0 + var tilecount: Int = 0 + var tileheight: Int = 0 + var tilewidth: Int = 0 + var tileproperties: MutableMap> = HashMap() } class TilesetIndex( - val texture: Texture?, - val tcLeft: Float, - val tcTop: Float, - val tcRight: Float, - val tcBottom: Float, - val scale: Float - ) { - constructor() : this(null, 0f, 0f, 0f, 0f, 0f) + val texture: Texture?, + val tcLeft: Float, + val tcTop: Float, + val tcRight: Float, + val tcBottom: Float, + val scale: Float +) { + constructor() : this(null, 0f, 0f, 0f, 0f, 0f) - fun render(x: Float, y: Float) { - texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) - } + fun render(x: Float, y: Float) { + texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) + } } class TiledMap(dir: String = "", url: String) { - val properties: Map = HashMap() - val data: MapData - val tileset: Array - val tiles: Array - var first = true - //var tilesetIndex: Array = Array(0, { TilesetIndex() }) + val properties: Map = HashMap() + val data: MapData + val tileset: Array + val tiles: Array + var first = true + //var tilesetIndex: Array = Array(0, { TilesetIndex() }) - init { - var tileDir = dir - if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { - tileDir = tileDir + "/" - } - - data = JSON.parse(getUrlAsString(tileDir + url)) - //println("map data is loaded") - val tilesets = data.tilesets - if (tilesets != null) { - tileset = Array(tilesets.size, { "" }) - var maxGid = 0 - for (index in 0..tilesets.size - 1) { - tileset[index] = tilesets[index].name - Textures.load(tilesets[index].name, tileDir + tilesets[index].image) - maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) - } - - tiles = Array(maxGid, { TilesetIndex() }) - } else { - tileset = Array(0, { "" }) - tiles = Array(0, { TilesetIndex() }) - } - - cacheTiles() + init { + var tileDir = dir + if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { + tileDir = tileDir + "/" } - fun cacheTiles() { - if (!Textures.ready()) { - window.setTimeout({ cacheTiles() }, 10) - } else { - val tilesets = data.tilesets - var tcLeft = 0f - var tcTop = 0f - var tcRight = 0f - var tcBottom = 0f + data = JSON.parse(getUrlAsString(tileDir + url)) + //println("map data is loaded") + val tilesets = data.tilesets + if (tilesets != null) { + tileset = Array(tilesets.size, { "" }) + var maxGid = 0 + for (index in 0..tilesets.size - 1) { + tileset[index] = tilesets[index].name + Textures.load(tilesets[index].name, tileDir + tilesets[index].image) + maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) + } - if (tilesets != null) { - - - for (tileset in tilesets) { - val tilesHor = tileset.imagewidth / tileset.tilewidth - val tilesVer = tileset.imageheight / tileset.tileheight - val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) - - for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { - val texture = Textures.get(tileset.name) - - val gid = index - tileset.firstgid - - val xi = gid % tilesHor - var yi = gid / tilesHor - yi = tilesVer - yi - 1 - val tw = 1f / tilesHor.toFloat() - val th = 1f / tilesVer.toFloat() - - val pixelW = 0.1f / tileset.tilewidth - val pixelH = 0.1f / tileset.tileheight - - tcLeft = xi * tw - tcRight = tcLeft + tw - - // switch up/down because of texture coord 0,0 in left bottom corner - tcBottom = yi * th - tcTop = tcBottom + th - - tcLeft += pixelW - tcRight -= pixelW - - tcBottom += pixelH - tcTop -= pixelH - - tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) - } - } - } - } + tiles = Array(maxGid, { TilesetIndex() }) + } else { + tileset = Array(0, { "" }) + tiles = Array(0, { TilesetIndex() }) } - fun drawTile(tile: Int, x: Float, y: Float) { - tiles[tile].render(x, y) + cacheTiles() + } + + fun cacheTiles() { + if (!Textures.ready()) { + window.setTimeout({ cacheTiles() }, 10) + } else { + val tilesets = data.tilesets + var tcLeft = 0f + var tcTop = 0f + var tcRight = 0f + var tcBottom = 0f + + if (tilesets != null) { + + + for (tileset in tilesets) { + val tilesHor = tileset.imagewidth / tileset.tilewidth + val tilesVer = tileset.imageheight / tileset.tileheight + val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) + + for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { + val texture = Textures.get(tileset.name) + + val gid = index - tileset.firstgid + + val xi = gid % tilesHor + var yi = gid / tilesHor + yi = tilesVer - yi - 1 + val tw = 1f / tilesHor.toFloat() + val th = 1f / tilesVer.toFloat() + + val pixelW = 0.1f / tileset.tilewidth + val pixelH = 0.1f / tileset.tileheight + + tcLeft = xi * tw + tcRight = tcLeft + tw + + // switch up/down because of texture coord 0,0 in left bottom corner + tcBottom = yi * th + tcTop = tcBottom + th + + tcLeft += pixelW + tcRight -= pixelW + + tcBottom += pixelH + tcTop -= pixelH + + tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) + } + } + } + } + } + + fun drawTile(tile: Int, x: Float, y: Float) { + tiles[tile].render(x, y) + } + + fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { + var x = 0f + var y = 0f + val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") + val layer = layers[layerIndex] + + val layerData = layer.data + if (layerData != null) { + for (index in layerData.indices) { + // todo: determine if in view + // todo: determine tilewidth + //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { + drawTile(layerData[index], xo + x * 128f, yo + y * 128f) + + when (data.renderorder) { + "right-down" -> { + x++ + if (x >= layer.width) { + x = 0f + y-- + } + } + else -> { + throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") + } + } + //} + } } - fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { - var x = 0f - var y = 0f - val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") - val layer = layers[layerIndex] + val tilesets = data.tilesets + if (tilesets != null) { + for (tileset in tilesets) { + if (Textures.has(tileset.name)) { + val tx = Textures.get(tileset.name) - val layerData = layer.data - if (layerData != null) { - for (index in layerData.indices) { - // todo: determine if in view - // todo: determine tilewidth - //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { - drawTile(layerData[index], xo + x * 128f, yo + y * 128f) - - when (data.renderorder) { - "right-down" -> { - x++ - if (x >= layer.width) { - x = 0f - y-- - } - } - else -> { - throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") - } - } - //} - } + tx.render() } - - val tilesets = data.tilesets - if (tilesets != null) { - for (tileset in tilesets) { - if (Textures.has(tileset.name)) { - val tx = Textures.get(tileset.name) - - tx.render() - } - } - } - - - first = false + } } + + + first = false + } } diff --git a/src/main/kotlin/games/perses/math/Matrix4.kt b/src/main/kotlin/games/perses/math/Matrix4.kt index 7da03cd..bd274bf 100644 --- a/src/main/kotlin/games/perses/math/Matrix4.kt +++ b/src/main/kotlin/games/perses/math/Matrix4.kt @@ -10,184 +10,184 @@ */ class Matrix4 { - internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - internal var temp = FloatArray(16) + internal var temp = FloatArray(16) - private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - fun get(): FloatArray { - return matrix + fun get(): FloatArray { + return matrix + } + + fun getFloat32Array() = Float32Array(get().toTypedArray()) + + fun set(values: FloatArray) { + if (values.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun getFloat32Array() = Float32Array(get().toTypedArray()) + matrix = values + } - fun set(values: FloatArray) { - if (values.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } + fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { + val r = (angle / 180f * Math.PI).toFloat() + val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() - matrix = values + matrix[0] = f / imageAspectRatio + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + + matrix[4] = 0.0f + matrix[5] = f + matrix[6] = 0.0f + matrix[7] = 0.0f + + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = -(far + near) / (far - near) + matrix[11] = -1.0f + + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = -(2.0f * far * near) / (far - near) + matrix[15] = 0.0f + } + + fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { + matrix[0] = 2f / (right - left) + matrix[1] = 0f + matrix[2] = 0f + matrix[3] = 0f + + matrix[4] = 0f + matrix[5] = 2f / (top - bottom) + matrix[6] = 0f + matrix[7] = 0f + + matrix[8] = 0f + matrix[9] = 0f + matrix[10] = -2f / (far - near) + matrix[11] = 0f + + matrix[12] = -(right + left) / (right - left) + matrix[13] = -(top + bottom) / (top - bottom) + matrix[14] = -(far + near) / (far - near) + matrix[15] = 1f + } + + fun setToIdentity() { + matrix[0] = 1.0f + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + matrix[4] = 0.0f + matrix[5] = 1.0f + matrix[6] = 0.0f + matrix[7] = 0.0f + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = 1.0f + matrix[11] = 0.0f + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = 0.0f + matrix[15] = 1.0f + } + + fun mul(other: Matrix4) { + mul(other.get()) + } + + protected fun mul(other: FloatArray) { + if (other.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { - val r = (angle / 180f * Math.PI).toFloat() - val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() + temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] + temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] + temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] + temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] + temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] + temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] + temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] + temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] + temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] + temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] + temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] + temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] + temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] + temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] + temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] + temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - matrix[0] = f / imageAspectRatio - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f + matrix[0] = temp[0] + matrix[1] = temp[1] + matrix[2] = temp[2] + matrix[3] = temp[3] + matrix[4] = temp[4] + matrix[5] = temp[5] + matrix[6] = temp[6] + matrix[7] = temp[7] + matrix[8] = temp[8] + matrix[9] = temp[9] + matrix[10] = temp[10] + matrix[11] = temp[11] + matrix[12] = temp[12] + matrix[13] = temp[13] + matrix[14] = temp[14] + matrix[15] = temp[15] + } - matrix[4] = 0.0f - matrix[5] = f - matrix[6] = 0.0f - matrix[7] = 0.0f + fun translate(x: Float, y: Float, z: Float) { + translateMatrix[12] = x + translateMatrix[13] = y + translateMatrix[14] = z - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = -(far + near) / (far - near) - matrix[11] = -1.0f + mul(translateMatrix) + } - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = -(2.0f * far * near) / (far - near) - matrix[15] = 0.0f - } + fun scale(x: Float, y: Float, z: Float) { + scaleMatrix[0] = x + scaleMatrix[5] = y + scaleMatrix[10] = z - fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { - matrix[0] = 2f / (right - left) - matrix[1] = 0f - matrix[2] = 0f - matrix[3] = 0f + mul(scaleMatrix) + } - matrix[4] = 0f - matrix[5] = 2f / (top - bottom) - matrix[6] = 0f - matrix[7] = 0f + fun rotateX(angle: Float) { + rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() + rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() + rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() + rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - matrix[8] = 0f - matrix[9] = 0f - matrix[10] = -2f / (far - near) - matrix[11] = 0f + mul(rotateXMatrix) + } - matrix[12] = - (right + left) / (right - left) - matrix[13] = - (top + bottom) / (top - bottom) - matrix[14] = - (far + near) / (far - near) - matrix[15] = 1f - } + fun rotateY(angle: Float) { + rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() + rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() + rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - fun setToIdentity() { - matrix[0] = 1.0f - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f - matrix[4] = 0.0f - matrix[5] = 1.0f - matrix[6] = 0.0f - matrix[7] = 0.0f - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = 1.0f - matrix[11] = 0.0f - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = 0.0f - matrix[15] = 1.0f - } + mul(rotateYMatrix) + } - fun mul(other: Matrix4) { - mul(other.get()) - } + fun rotateZ(angle: Float) { + rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() + rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() + rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - protected fun mul(other: FloatArray) { - if (other.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } - - temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] - temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] - temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] - temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] - temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] - temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] - temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] - temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] - temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] - temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] - temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] - temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] - temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] - temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] - temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] - temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - - matrix[0] = temp[0] - matrix[1] = temp[1] - matrix[2] = temp[2] - matrix[3] = temp[3] - matrix[4] = temp[4] - matrix[5] = temp[5] - matrix[6] = temp[6] - matrix[7] = temp[7] - matrix[8] = temp[8] - matrix[9] = temp[9] - matrix[10] = temp[10] - matrix[11] = temp[11] - matrix[12] = temp[12] - matrix[13] = temp[13] - matrix[14] = temp[14] - matrix[15] = temp[15] - } - - fun translate(x: Float, y: Float, z: Float) { - translateMatrix[12] = x - translateMatrix[13] = y - translateMatrix[14] = z - - mul(translateMatrix) - } - - fun scale(x: Float, y: Float, z: Float) { - scaleMatrix[0] = x - scaleMatrix[5] = y - scaleMatrix[10] = z - - mul(scaleMatrix) - } - - fun rotateX(angle: Float) { - rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() - rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() - rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() - rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateXMatrix) - } - - fun rotateY(angle: Float) { - rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() - rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() - rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateYMatrix) - } - - fun rotateZ(angle: Float) { - rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() - rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() - rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateZMatrix) - } + mul(rotateZMatrix) + } } diff --git a/src/main/kotlin/games/perses/net/NetUtils.kt b/src/main/kotlin/games/perses/net/NetUtils.kt index 5b5b820..148b920 100644 --- a/src/main/kotlin/games/perses/net/NetUtils.kt +++ b/src/main/kotlin/games/perses/net/NetUtils.kt @@ -9,10 +9,10 @@ */ fun getUrlAsString(url: String): String { - val req = XMLHttpRequest() + val req = XMLHttpRequest() - req.open("GET", url, false) - req.send(null) + req.open("GET", url, false) + req.send(null) - return req.responseText + return req.responseText } diff --git a/src/main/kotlin/games/perses/shader/ShaderProgram.kt b/src/main/kotlin/games/perses/shader/ShaderProgram.kt index cf07c0f..7dde03a 100644 --- a/src/main/kotlin/games/perses/shader/ShaderProgram.kt +++ b/src/main/kotlin/games/perses/shader/ShaderProgram.kt @@ -1,6 +1,10 @@ package games.perses.shader -import org.khronos.webgl.* +import org.khronos.webgl.Float32Array +import org.khronos.webgl.WebGLBuffer +import org.khronos.webgl.WebGLProgram +import org.khronos.webgl.WebGLRenderingContext +import org.khronos.webgl.WebGLShader /** * User: rnentjes @@ -9,103 +13,125 @@ */ class ShaderProgram( - val webgl: WebGLRenderingContext, - val drawType: Int, - vertexShaderSource: String, - fragmentShaderSource: String, - val vainfo: Array, - val setter: (program: ShaderProgram, data: T) -> Unit) { + val webgl: WebGLRenderingContext, + val drawType: Int, + vertexShaderSource: String, + fragmentShaderSource: String, + val vainfo: Array, + val setter: (program: ShaderProgram, data: T) -> Unit +) { - var shaderProgram: WebGLProgram - var vertex: WebGLShader - var fragment: WebGLShader + var shaderProgram: WebGLProgram + var vertex: WebGLShader + var fragment: WebGLShader - var verticesBlockSize = 0 - var drawLength = 0 + var verticesBlockSize = 0 + var drawLength = 0 - init { - vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER) - fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER) + init { + vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER) + fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER) - shaderProgram = webgl.createProgram() ?: throw IllegalStateException("Unable to request shader program from webgl context!") - webgl.attachShader(shaderProgram, vertex) - webgl.attachShader(shaderProgram, fragment) - webgl.linkProgram(shaderProgram) + shaderProgram = webgl.createProgram() ?: throw IllegalStateException( + "Unable to request shader program from webgl context!" + ) + webgl.attachShader(shaderProgram, vertex) + webgl.attachShader(shaderProgram, fragment) + webgl.linkProgram(shaderProgram) - if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) { - //println(webgl.getProgramInfoLog(shaderProgram)) - throw IllegalStateException("Unable to compile shader program!") - } - - webgl.useProgram(shaderProgram) - - this.verticesBlockSize = 0 - - // set attribute locations... - for (info in vainfo.iterator()) { - info.location = webgl.getAttribLocation(shaderProgram, info.locationName) - info.offset = verticesBlockSize - - verticesBlockSize += info.numElements - //println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}") - } - - when(drawType) { - WebGLRenderingContext.TRIANGLES -> { - drawLength = verticesBlockSize * 3 - } - else -> { - drawLength = verticesBlockSize - } - } - - //println("verticesBlockSize $verticesBlockSize") - - //println("ShaderProgram constructor done") + if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) { + //println(webgl.getProgramInfoLog(shaderProgram)) + throw IllegalStateException("Unable to compile shader program!") } - private fun compileShader(source: String, type: Int): WebGLShader { - val result: WebGLShader = webgl.createShader(type) ?: throw IllegalStateException("Unable to request shader from webgl context!") + webgl.useProgram(shaderProgram) - webgl.shaderSource(result, source) - webgl.compileShader(result) + this.verticesBlockSize = 0 - if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) { - throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}") - } + // set attribute locations... + for (info in vainfo.iterator()) { + info.location = webgl.getAttribLocation(shaderProgram, info.locationName) + info.offset = verticesBlockSize - return result + verticesBlockSize += info.numElements + //println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}") } - fun begin(attribBuffer: WebGLBuffer, userdata: T) { - webgl.useProgram(shaderProgram); - webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); - - // set attribute locations... - for (info in vainfo.iterator()) { - webgl.enableVertexAttribArray(info.location) - webgl.vertexAttribPointer(info.location, info.numElements, WebGLRenderingContext.FLOAT, false, verticesBlockSize * 4, info.offset * 4) - } - - setter(this, userdata) + when (drawType) { + WebGLRenderingContext.TRIANGLES -> { + drawLength = verticesBlockSize * 3 + } + else -> { + drawLength = verticesBlockSize + } } - fun end() { - for (info in vainfo.iterator()) { - webgl.disableVertexAttribArray(info.location); - } - webgl.useProgram(null) + //println("verticesBlockSize $verticesBlockSize") + + //println("ShaderProgram constructor done") + } + + private fun compileShader(source: String, type: Int): WebGLShader { + val result: WebGLShader = webgl.createShader(type) + ?: throw IllegalStateException("Unable to request shader from webgl context!") + + webgl.shaderSource(result, source) + webgl.compileShader(result) + + if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) { + throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}") } - fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location); + return result + } - fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location); + fun begin(attribBuffer: WebGLBuffer, userdata: T) { + webgl.useProgram(shaderProgram); + webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); - fun setUniform1f(location: String, value: Float) { webgl.uniform1f(getUniformLocation(location), value); } - fun setUniform2f(location: String, v1: Float, v2: Float) { webgl.uniform2f(getUniformLocation(location), v1, v2); } - fun setUniform3f(location: String, v1: Float, v2: Float, v3: Float) { webgl.uniform3f(getUniformLocation(location), v1, v2, v3); } - fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); } - fun setUniform1i(location: String, value: Int) { webgl.uniform1i(getUniformLocation(location), value); } - fun setUniformMatrix4fv(location: String, value: Float32Array) { webgl.uniformMatrix4fv(getUniformLocation(location), false, value); } + // set attribute locations... + for (info in vainfo.iterator()) { + webgl.enableVertexAttribArray(info.location) + webgl.vertexAttribPointer( + info.location, + info.numElements, + WebGLRenderingContext.FLOAT, + false, + verticesBlockSize * 4, + info.offset * 4 + ) + } + + setter(this, userdata) + } + + fun end() { + for (info in vainfo.iterator()) { + webgl.disableVertexAttribArray(info.location); + } + webgl.useProgram(null) + } + + fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location); + + fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location); + + fun setUniform1f(location: String, value: Float) { + webgl.uniform1f(getUniformLocation(location), value); } + + fun setUniform2f(location: String, v1: Float, v2: Float) { + webgl.uniform2f(getUniformLocation(location), v1, v2); } + + fun setUniform3f(location: String, v1: Float, v2: Float, v3: Float) { + webgl.uniform3f(getUniformLocation(location), v1, v2, v3); } + + fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { + webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); } + + fun setUniform1i(location: String, value: Int) { + webgl.uniform1i(getUniformLocation(location), value); } + + fun setUniformMatrix4fv(location: String, value: Float32Array) { + webgl.uniformMatrix4fv(getUniformLocation(location), false, value); } } diff --git a/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt b/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt index d9a3908..d65cf7f 100644 --- a/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt +++ b/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt @@ -11,64 +11,67 @@ * Time: 11:57 */ -class VertextAttributeInfo(val locationName: String, val numElements: Int) { - var location = 0 - var offset = 0 +class VertextAttributeInfo( + val locationName: String, + val numElements: Int +) { + var location = 0 + var offset = 0 } class ShaderProgramMesh( - val shaderProgram: ShaderProgram + val shaderProgram: ShaderProgram ) { - val webgl = shaderProgram.webgl - val data: Float32Array = Float32Array(20000 - (20000 % shaderProgram.drawLength)) - var currentIndex: Int = 0 - val attribBuffer: WebGLBuffer - var counter = 0 + val webgl = shaderProgram.webgl + val data: Float32Array = Float32Array(20000 - (20000 % shaderProgram.drawLength)) + var currentIndex: Int = 0 + val attribBuffer: WebGLBuffer + var counter = 0 - init { - attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!") - webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer) + init { + attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!") + webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer) + } + + fun queue(vararg vertices: Float) { + for (vertice in vertices) { + data[currentIndex++] = vertice } - fun queue(vararg vertices: Float) { - for (vertice in vertices) { - data[currentIndex++] = vertice - } - - if (bufferFull()) { - println("Skipped draw call, to many values!") - currentIndex = 0 - } + if (bufferFull()) { + println("Skipped draw call, to many values!") + currentIndex = 0 } + } - fun queueArray(vertices: Array) { - data.set(vertices, currentIndex) - currentIndex += vertices.size + fun queueArray(vertices: Array) { + data.set(vertices, currentIndex) + currentIndex += vertices.size - if (bufferFull()) { - println("Skipped draw call, to many values!") - currentIndex = 0 - } + if (bufferFull()) { + println("Skipped draw call, to many values!") + currentIndex = 0 } + } - fun remaining() = data.length - currentIndex + fun remaining() = data.length - currentIndex - fun bufferFull() = currentIndex == data.length + fun bufferFull() = currentIndex == data.length - fun render(userdata: T) { - counter++ - if (currentIndex > 0) { - if (currentIndex % shaderProgram.verticesBlockSize != 0) { - throw IllegalStateException("Number of vertices not a multiple of the attribute block size!") - } + fun render(userdata: T) { + counter++ + if (currentIndex > 0) { + if (currentIndex % shaderProgram.verticesBlockSize != 0) { + throw IllegalStateException("Number of vertices not a multiple of the attribute block size!") + } - shaderProgram.begin(attribBuffer, userdata) + shaderProgram.begin(attribBuffer, userdata) - webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW) - webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize)) - currentIndex = 0 + webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW) + webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize)) + currentIndex = 0 - shaderProgram.end() - } + shaderProgram.end() } + } } diff --git a/src/main/kotlin/games/perses/sound/Music.kt b/src/main/kotlin/games/perses/sound/Music.kt index a3fcccc..c5ddadf 100644 --- a/src/main/kotlin/games/perses/sound/Music.kt +++ b/src/main/kotlin/games/perses/sound/Music.kt @@ -10,43 +10,43 @@ */ fun HTMLAudioElement.dispose() { - this.pause() - this.parentNode?.removeChild(this) + this.pause() + this.parentNode?.removeChild(this) } object Music { - val playing: MutableSet = HashSet() + val playing: MutableSet = HashSet() - fun load(url: String): HTMLAudioElement { - val audio = document.createElement("audio") as HTMLAudioElement + fun load(url: String): HTMLAudioElement { + val audio = document.createElement("audio") as HTMLAudioElement - audio.src = url + audio.src = url - return audio - } + return audio + } - fun play(url: String, volume: Double = 0.75, looping: Boolean = false): HTMLAudioElement { - val audio = document.createElement("audio") as HTMLAudioElement + fun play(url: String, volume: Double = 0.75, looping: Boolean = false): HTMLAudioElement { + val audio = document.createElement("audio") as HTMLAudioElement - audio.src = url - audio.volume = volume + audio.src = url + audio.volume = volume + audio.play() + + audio.onended = { + if (looping) { + audio.currentTime = 0.0 audio.play() - - audio.onended = { - if (looping) { - audio.currentTime = 0.0 - audio.play() - } else { - //println("REMOVING: $audio") - audio.parentNode?.removeChild(audio) - playing.remove(audio) - } - } - - return audio + } else { + //println("REMOVING: $audio") + audio.parentNode?.removeChild(audio) + playing.remove(audio) + } } - fun stopAll() { + return audio + } - } + fun stopAll() { + + } } diff --git a/src/main/kotlin/games/perses/sound/Sounds.kt b/src/main/kotlin/games/perses/sound/Sounds.kt index f866817..f00aa06 100644 --- a/src/main/kotlin/games/perses/sound/Sounds.kt +++ b/src/main/kotlin/games/perses/sound/Sounds.kt @@ -9,83 +9,88 @@ * Time: 12:34 */ -class Sound(val name:String, val url: String, val defaultVolume: Double = 0.75, val numberOfChannels: Int) { - var channels: Array = +class Sound( + val name: String, + val url: String, + val defaultVolume: Double = 0.75, + val numberOfChannels: Int +) { + var channels: Array = Array(numberOfChannels, { document.createElement("audio") as HTMLAudioElement }) - var nextChannel: Int = 0 + var nextChannel: Int = 0 - init { - //println("CREATING: $name") + init { + //println("CREATING: $name") - for (audio in channels) { - if (audio != null) { - audio.src = url - audio.pause() - audio.load() - audio.volume = defaultVolume - } - } + for (audio in channels) { + if (audio != null) { + audio.src = url + audio.pause() + audio.load() + audio.volume = defaultVolume + } } + } - fun play(volume: Double = defaultVolume) { - //println("PLAYING: $name - $nextChannel") - channels[nextChannel]?.volume = volume - channels[nextChannel]?.currentTime = 0.0 - channels[nextChannel]?.play() + fun play(volume: Double = defaultVolume) { + //println("PLAYING: $name - $nextChannel") + channels[nextChannel]?.volume = volume + channels[nextChannel]?.currentTime = 0.0 + channels[nextChannel]?.play() - nextChannel = (nextChannel + 1) % channels.size + nextChannel = (nextChannel + 1) % channels.size + } + + fun pause() { + for (audio in channels) { + audio?.pause() } + } - fun pause() { - for (audio in channels) { - audio?.pause() - } + fun dispose() { + for (audio in channels) { + audio?.dispose() } - - fun dispose() { - for (audio in channels) { - audio?.dispose() - } - } + } } object Sounds { - val sounds: MutableMap = HashMap() + val sounds: MutableMap = HashMap() - fun load(name: String, url: String, volume: Double = 0.75, channels: Int = 1 ) { - sounds.put(name, Sound(name, url, volume, channels)) + fun load(name: String, url: String, volume: Double = 0.75, channels: Int = 1) { + sounds.put(name, Sound(name, url, volume, channels)) + } + + fun play(name: String, volume: Double? = null) { + val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!") + + if (volume != null) { + sound.play(volume) + } else { + sound.play() + } + } + + fun pause(name: String) { + val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!") + + sound.pause() + } + + fun dispose(name: String) { + val sound: Sound? = sounds[name] + + if (sound != null) { + sounds.remove(name) + sound.dispose() + } + } + + fun disposeAll() { + for (sound in sounds.values) { + sound.dispose() } - fun play(name: String, volume: Double? = null) { - val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!") - - if (volume != null) { - sound.play(volume) - } else { - sound.play() - } - } - - fun pause(name: String) { - val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!") - - sound.pause() - } - - fun dispose(name: String) { - val sound: Sound? = sounds[name] - - if (sound != null) { - sounds.remove(name) - sound.dispose() - } - } - - fun disposeAll() { - for (sound in sounds.values) { - sound.dispose() - } - - sounds.clear() - } + sounds.clear() + } } diff --git a/src/main/kotlin/games/perses/sprite/SpriteBatch.kt b/src/main/kotlin/games/perses/sprite/SpriteBatch.kt index 3de1163..f0b4557 100644 --- a/src/main/kotlin/games/perses/sprite/SpriteBatch.kt +++ b/src/main/kotlin/games/perses/sprite/SpriteBatch.kt @@ -10,17 +10,17 @@ */ class Sprite(val textureName: String) { - val texture: Texture by lazy { Textures.get(textureName) } + val texture: Texture by lazy { Textures[textureName] } } class SpriteBatch { - fun draw(sprite: Sprite, x: Float, y: Float, scale: Float = 1f, rotation: Float = 0f) { - sprite.texture.queueDraw(x, y, scale, rotation) - } + fun draw(sprite: Sprite, x: Float, y: Float, scale: Float = 1f, rotation: Float = 0f) { + sprite.texture.queueDraw(x, y, scale, rotation) + } - fun render() { - Textures.render() - } + fun render() { + Textures.render() + } } diff --git a/src/main/kotlin/games/perses/text/Texts.kt b/src/main/kotlin/games/perses/text/Texts.kt index 52d1a0d..7c71073 100644 --- a/src/main/kotlin/games/perses/text/Texts.kt +++ b/src/main/kotlin/games/perses/text/Texts.kt @@ -7,31 +7,43 @@ */ object Texts { - // TODO: use same coords for webgl and canvas 2d - fun drawText(x: Float, y: Float, message: String, font: String = "bold 24pt Arial", fillStyle: String = "white") { - var yy = y - var xx = x - if (yy < 0) { - yy += Game.view.height - } - if (xx < 0) { - xx += Game.view.width - } - yy = Game.view.height - yy - - Game.html.canvas2d.fillStyle = fillStyle - Game.html.canvas2d.font = font - Game.html.canvas2d.fillText(message, x.toDouble(), yy.toDouble()) + // TODO: use same coords for webgl and canvas 2d + fun drawText( + x: Float, + y: Float, + message: String, + font: String = "bold 24pt Arial", + fillStyle: String = "white" + ) { + var yy = y + var xx = x + if (yy < 0) { + yy += Game.view.height } - - fun drawLeftTop(left: Float, top: Float, message: String, font: String = "bold 24pt Arial", fillStyle: String = "white") { - drawText( - left, - /* Game.view.height - */ top, - message, - font, - fillStyle - ) + if (xx < 0) { + xx += Game.view.width } + yy = Game.view.height - yy + + Game.html.canvas2d.fillStyle = fillStyle + Game.html.canvas2d.font = font + Game.html.canvas2d.fillText(message, x.toDouble(), yy.toDouble()) + } + + fun drawLeftTop( + left: Float, + top: Float, + message: String, + font: String = "bold 24pt Arial", + fillStyle: String = "white" + ) { + drawText( + left, + /* Game.view.height - */ top, + message, + font, + fillStyle + ) + } } diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml new file mode 100644 index 0000000..6c33f1c --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_js_1_2_30.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml index 7fe6290..53a67e1 100644 --- a/.idea/modules/kudens.iml +++ b/.idea/modules/kudens.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml index 1ecd401..5c1afc5 100644 --- a/.idea/modules/kudens_main.iml +++ b/.idea/modules/kudens_main.iml @@ -1,5 +1,5 @@ - + @@ -35,8 +35,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml index 43edcc2..7ed1494 100644 --- a/.idea/modules/kudens_test.iml +++ b/.idea/modules/kudens_test.iml @@ -1,8 +1,9 @@ - + + $MODULE_DIR$/../../build/kotlinjs/kudens.js \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7ae9969..e7225a0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'perses.games' -version '1.1.6-SNAPSHOT' +version '1.1.7-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'idea' @@ -20,7 +20,7 @@ } buildscript { - ext.kotlin_version = '1.2.21' + ext.kotlin_version = '1.2.30' repositories { maven { url "http://nexus.astraeus.nl/nexus/content/groups/public" diff --git a/src/main/kotlin/games/perses/color/Color.kt b/src/main/kotlin/games/perses/color/Color.kt index 7f235b0..31b540f 100644 --- a/src/main/kotlin/games/perses/color/Color.kt +++ b/src/main/kotlin/games/perses/color/Color.kt @@ -10,107 +10,107 @@ object Color { - /** - * Converts an HSL color value to RGB. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes h, s, and l are contained in the set [0, 1] and - * returns r, g, and b in the set [0, 255]. + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. - * @param h The hue - * * - * @param s The saturation - * * - * @param l The lightness - * * - * @return int array, the RGB representation - */ - fun hslToRgb(h: Float, s: Float, l: Float): IntArray { - val r: Float - val g: Float - val b: Float + * @param h The hue + * * + * @param s The saturation + * * + * @param l The lightness + * * + * @return int array, the RGB representation + */ + fun hslToRgb(h: Float, s: Float, l: Float): IntArray { + val r: Float + val g: Float + val b: Float - if (s == 0f) { - b = l - g = b - r = g // achromatic - } else { - val q = if (l < 0.5f) l * (1 + s) else l + s - l * s - val p = 2 * l - q - r = hueToRgb(p, q, h + 1f / 3f) - g = hueToRgb(p, q, h) - b = hueToRgb(p, q, h - 1f / 3f) - } - val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) + if (s == 0f) { + b = l + g = b + r = g // achromatic + } else { + val q = if (l < 0.5f) l * (1 + s) else l + s - l * s + val p = 2 * l - q + r = hueToRgb(p, q, h + 1f / 3f) + g = hueToRgb(p, q, h) + b = hueToRgb(p, q, h - 1f / 3f) + } + val rgb = intArrayOf((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt()) - return rgb + return rgb + } + + /** Helper method that converts hue to rgb */ + fun hueToRgb(p: Float, q: Float, t: Float): Float { + var lt = t + if (lt < 0f) { + lt += 1f + } + if (lt > 1f) { + lt -= 1f + } + if (lt < 1f / 6f) { + return p + (q - p) * 6f * lt + } + if (lt < 1f / 2f) { + return q + } + if (lt < 2f / 3f) { + return p + (q - p) * (2f / 3f - lt) * 6f + } + return p + } + + /** + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes pR, pG, and bpBare contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + + * @param pR The red color value + * * + * @param pG The green color value + * * + * @param pB The blue color value + * * + * @return float array, the HSL representation + */ + fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { + val r = pR / 255f + val g = pG / 255f + val b = pB / 255f + + val max = if (r > g && r > b) r else if (g > b) g else b + val min = if (r < g && r < b) r else if (g < b) g else b + + var h: Float + val s: Float + val l: Float + l = (max + min) / 2.0f + + if (max == min) { + s = 0.0f + h = s + } else { + val d = max - min + s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) + + if (r > g && r > b) + h = (g - b) / d + (if (g < b) 6.0f else 0.0f) + else if (g > b) + h = (b - r) / d + 2.0f + else + h = (r - g) / d + 4.0f + + h /= 6.0f } - /** Helper method that converts hue to rgb */ - fun hueToRgb(p: Float, q: Float, t: Float): Float { - var lt = t - if (lt < 0f) { - lt += 1f - } - if (lt > 1f) { - lt -= 1f - } - if (lt < 1f / 6f) { - return p + (q - p) * 6f * lt - } - if (lt < 1f / 2f) { - return q - } - if (lt < 2f / 3f) { - return p + (q - p) * (2f / 3f - lt) * 6f - } - return p - } - - /** - * Converts an RGB color value to HSL. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes pR, pG, and bpBare contained in the set [0, 255] and - * returns h, s, and l in the set [0, 1]. - - * @param pR The red color value - * * - * @param pG The green color value - * * - * @param pB The blue color value - * * - * @return float array, the HSL representation - */ - fun rgbToHsl(pR: Int, pG: Int, pB: Int): FloatArray { - val r = pR / 255f - val g = pG / 255f - val b = pB / 255f - - val max = if (r > g && r > b) r else if (g > b) g else b - val min = if (r < g && r < b) r else if (g < b) g else b - - var h: Float - val s: Float - val l: Float - l = (max + min) / 2.0f - - if (max == min) { - s = 0.0f - h = s - } else { - val d = max - min - s = if (l > 0.5f) d / (2.0f - max - min) else d / (max + min) - - if (r > g && r > b) - h = (g - b) / d + (if (g < b) 6.0f else 0.0f) - else if (g > b) - h = (b - r) / d + 2.0f - else - h = (r - g) / d + 4.0f - - h /= 6.0f - } - - val hsl = floatArrayOf(h, s, l) - return hsl - } + val hsl = floatArrayOf(h, s, l) + return hsl + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/game/Game.kt b/src/main/kotlin/games/perses/game/Game.kt index 0961316..1becee5 100644 --- a/src/main/kotlin/games/perses/game/Game.kt +++ b/src/main/kotlin/games/perses/game/Game.kt @@ -14,210 +14,210 @@ */ enum class DrawMode { - LINEAR, - NEAREST + LINEAR, + NEAREST } class HTMLElements { - var container: HTMLElement - var webgl: WebGLRenderingContext - var canvas2d: CanvasRenderingContext2D + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D - init { - container = document.createElement("div") as HTMLElement + init { + container = document.createElement("div") as HTMLElement - val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement - val canvas = document.createElement("canvas") as HTMLCanvasElement + val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + val canvas = document.createElement("canvas") as HTMLCanvasElement - container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") - webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" ) - canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" ) + container.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;") + canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;") - document.body!!.appendChild(container) - container.appendChild(webGlCanvas) - container.appendChild(canvas) + document.body!!.appendChild(container) + container.appendChild(webGlCanvas) + container.appendChild(canvas) - val canvas2dcanvas = canvas.getContext("2d") + val canvas2dcanvas = canvas.getContext("2d") - var webglcanvas = webGlCanvas.getContext("webgl") - if (webglcanvas == null) { - console.log("webgl context not found, trying experimental-webgl.") - webglcanvas = webGlCanvas.getContext("experimental-webgl") - } - - if (webglcanvas != null) { - webgl = webglcanvas as WebGLRenderingContext - } else { - console.log("webgl?", webglcanvas) - window.alert("Your browser doesn't seem to support webgl!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } - - if (canvas2dcanvas != null) { - canvas2d = canvas2dcanvas as CanvasRenderingContext2D - } else { - console.log("canvas2d?", canvas2dcanvas) - window.alert("Your browser doesn't seem to support 2d canvas!") - - throw IllegalStateException("Your browser doesn't seem to support webgl!") - } + var webglcanvas = webGlCanvas.getContext("webgl") + if (webglcanvas == null) { + console.log("webgl context not found, trying experimental-webgl.") + webglcanvas = webGlCanvas.getContext("experimental-webgl") } + + if (webglcanvas != null) { + webgl = webglcanvas as WebGLRenderingContext + } else { + console.log("webgl?", webglcanvas) + window.alert("Your browser doesn't seem to support webgl!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + + if (canvas2dcanvas != null) { + canvas2d = canvas2dcanvas as CanvasRenderingContext2D + } else { + console.log("canvas2d?", canvas2dcanvas) + window.alert("Your browser doesn't seem to support 2d canvas!") + + throw IllegalStateException("Your browser doesn't seem to support webgl!") + } + } } object Game { - var started = false - val view: View = View() - val html: HTMLElements by lazy { HTMLElements() } - var currentScreen: Screen = DefaultScreen() - var start = Date().getTime() - var currentTime = start - var currentDelta = 0f - var pause: Boolean = false - var clearScreenEveryFrame = true + var started = false + val view: View = View() + val html: HTMLElements by lazy { HTMLElements() } + var currentScreen: Screen = DefaultScreen() + var start = Date().getTime() + var currentTime = start + var currentDelta = 0f + var pause: Boolean = false + var clearScreenEveryFrame = true - var clearRed = 0f - var clearGreen = 0f - var clearBlue = 0f - var clearAlpha = 1f + var clearRed = 0f + var clearGreen = 0f + var clearBlue = 0f + var clearAlpha = 1f - var fps = 0 - var fpsCount = 0 - var fpsCountTime = 0f + var fps = 0 + var fpsCount = 0 + var fpsCountTime = 0f - var borderLeft = 0 - var borderTop = 0 + var borderLeft = 0 + var borderTop = 0 - var focus = true + var focus = true - init { - window.onfocus = { - //println("GOT FOCUS!") + init { + window.onfocus = { + //println("GOT FOCUS!") - focus = true - "" - } - window.onblur = { - //println("LOST FOCUS!") + focus = true + "" + } + window.onblur = { + //println("LOST FOCUS!") - focus = false - "" - } - + focus = false + "" } - fun gl() = html.webgl + } - fun resize() { - val canvas = gl().canvas + fun gl() = html.webgl - // Check if the canvas is not the same size. - val windowWidth = window.innerWidth.toInt() - val windowHeight = window.innerHeight.toInt() + fun resize() { + val canvas = gl().canvas - if (view.lastWindowWidth != windowWidth || - view.lastWindowHeight != windowHeight) { - view.lastWindowWidth = windowWidth - view.lastWindowHeight = windowHeight - view.windowWidth = windowWidth - view.windowHeight = windowHeight + // Check if the canvas is not the same size. + val windowWidth = window.innerWidth.toInt() + val windowHeight = window.innerHeight.toInt() - view.updateView() + if (view.lastWindowWidth != windowWidth || + view.lastWindowHeight != windowHeight) { + view.lastWindowWidth = windowWidth + view.lastWindowHeight = windowHeight + view.windowWidth = windowWidth + view.windowHeight = windowHeight - val textCanvas = html.canvas2d.canvas + view.updateView() - // Make the canvas the same size - canvas.width = view.width.toInt() - canvas.height = view.height.toInt() + val textCanvas = html.canvas2d.canvas - textCanvas.width = view.width.toInt() - textCanvas.height = view.height.toInt() + // Make the canvas the same size + canvas.width = view.width.toInt() + canvas.height = view.height.toInt() - gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) + textCanvas.width = view.width.toInt() + textCanvas.height = view.height.toInt() - borderLeft = (windowWidth - view.windowWidth) / 2 - borderTop = (windowHeight - view.windowHeight) / 2 + gl().viewport(0, 0, view.width.toInt(), view.height.toInt()) - canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) - textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" ) + borderLeft = (windowWidth - view.windowWidth) / 2 + borderTop = (windowHeight - view.windowHeight) / 2 + + canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;") + } + } + + fun start(startScreen: Screen) { + if (started) { + throw IllegalStateException("You can only start a game once!") + } + + setScreen(startScreen) + + // start game loop + started = true + gameLoop() + } + + fun setScreen(screen: Screen) { + currentScreen.unloadResources() + + currentScreen = screen + + screen.loadResources() + } + + fun setClearColor(r: Float, g: Float, b: Float, a: Float) { + clearRed = r + clearGreen = g + clearBlue = b + clearAlpha = a + } + + fun gameLoop() { + try { + if (!Textures.ready()) { + gl().clearColor(1f, 1f, 1f, 1f) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } else { + resize() + + if (!pause) { + html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); + + if (clearScreenEveryFrame) { + gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) + gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } + + gl().enable(WebGLRenderingContext.BLEND) + gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); + + val time = Date().getTime() + currentDelta = ((time - currentTime) / 1000f).toFloat() + currentTime = time + + val timeInSeconds = (currentTime - start) / 1000f + + fpsCountTime += currentDelta + fpsCount++ + while (fpsCountTime > 1f) { + fps = fpsCount + fpsCountTime -= 1f + fpsCount = 0 + } + + if (focus) { + currentScreen.update(timeInSeconds.toFloat(), currentDelta) + } + + currentScreen.render() } + } + } catch (e: Exception) { + println("Some error...") + console.log(e) } - fun start(startScreen: Screen) { - if (started) { - throw IllegalStateException("You can only start a game once!") - } - - setScreen(startScreen) - - // start game loop - started = true - gameLoop() + window.requestAnimationFrame { + gameLoop() } - - fun setScreen(screen: Screen) { - currentScreen.unloadResources() - - currentScreen = screen - - screen.loadResources() - } - - fun setClearColor(r: Float, g: Float, b: Float, a: Float) { - clearRed = r - clearGreen = g - clearBlue = b - clearAlpha = a - } - - fun gameLoop() { - try { - if (!Textures.ready()) { - gl().clearColor(1f, 1f, 1f, 1f) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } else { - resize() - - if (!pause) { - html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble()); - - if (clearScreenEveryFrame) { - gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha) - gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } - - gl().enable(WebGLRenderingContext.BLEND) - gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA); - - val time = Date().getTime() - currentDelta = ((time - currentTime) / 1000f).toFloat() - currentTime = time - - val timeInSeconds = (currentTime - start) / 1000f - - fpsCountTime += currentDelta - fpsCount++ - while (fpsCountTime > 1f) { - fps = fpsCount - fpsCountTime -= 1f - fpsCount = 0 - } - - if (focus) { - currentScreen.update(timeInSeconds.toFloat(), currentDelta) - } - - currentScreen.render() - } - } - } catch(e: Exception) { - println("Some error...") - console.log(e) - } - - window.requestAnimationFrame { - gameLoop() - } - } + } } diff --git a/src/main/kotlin/games/perses/game/Screen.kt b/src/main/kotlin/games/perses/game/Screen.kt index 10b6eae..7b381e7 100644 --- a/src/main/kotlin/games/perses/game/Screen.kt +++ b/src/main/kotlin/games/perses/game/Screen.kt @@ -8,31 +8,31 @@ abstract class Screen { - open fun loadResources() {} + open fun loadResources() {} - @Deprecated( + @Deprecated( message = "replace with unloadResources", replaceWith = ReplaceWith("unloadResources()") - ) - open fun closeResources() { - unloadResources() - } + ) + open fun closeResources() { + unloadResources() + } - open fun unloadResources() {} + open fun unloadResources() {} - abstract fun update(time: Float, delta: Float) + abstract fun update(time: Float, delta: Float) - abstract fun render() + abstract fun render() } -class DefaultScreen: Screen() { - override fun update(time: Float, delta: Float) { - } +class DefaultScreen : Screen() { + override fun update(time: Float, delta: Float) { + } - override fun render() { - // show loading message? - Game.gl().clearColor(1f, 1f, 0f, 1f) - Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) - } + override fun render() { + // show loading message? + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + } } diff --git a/src/main/kotlin/games/perses/game/View.kt b/src/main/kotlin/games/perses/game/View.kt index 540a44d..16c9913 100644 --- a/src/main/kotlin/games/perses/game/View.kt +++ b/src/main/kotlin/games/perses/game/View.kt @@ -4,39 +4,39 @@ import kotlin.browser.document enum class ViewType { - PROJECTION, - WIDTH, - HEIGHT, - ABSOLUTE + PROJECTION, + WIDTH, + HEIGHT, + ABSOLUTE } class View( - var lastWindowWidth: Int = 2000, - var lastWindowHeight: Int = 1000, - var windowWidth: Int = 2000, - var windowHeight: Int = 1000, - var width: Float = 1024f, - var height: Float = 1024f, - var angle: Float = 60f, - var near: Float = -0.1f, - var far: Float = -100f, - var minAspectRatio: Float = 1f, - var maxAspectRatio: Float = 1f, - var leftOffset: Int = 0, - var bottomOffset: Int = 0, - var viewType: ViewType = ViewType.WIDTH, - var drawMode: DrawMode = DrawMode.LINEAR) { - var vMatrix = Matrix4() - var aspectRatio = 1f + var lastWindowWidth: Int = 2000, + var lastWindowHeight: Int = 1000, + var windowWidth: Int = 2000, + var windowHeight: Int = 1000, + var width: Float = 1024f, + var height: Float = 1024f, + var angle: Float = 60f, + var near: Float = -0.1f, + var far: Float = -100f, + var minAspectRatio: Float = 1f, + var maxAspectRatio: Float = 1f, + var leftOffset: Int = 0, + var bottomOffset: Int = 0, + var viewType: ViewType = ViewType.WIDTH, + var drawMode: DrawMode = DrawMode.LINEAR) { + var vMatrix = Matrix4() + var aspectRatio = 1f - init { - updateView() - } + init { + updateView() + } - fun requestFullscreen() { - val element = document.body - //language=javascript - js(""" + fun requestFullscreen() { + val element = document.body + //language=javascript + js(""" if(element.requestFullscreen) { element.requestFullscreen(); } else if(element.mozRequestFullScreen) { @@ -47,10 +47,10 @@ element.msRequestFullscreen(); } """) - } + } - fun exitFullscreen() { - js(""" + fun exitFullscreen() { + js(""" if(document.exitFullscreen) { document.exitFullscreen(); } else if(document.mozCancelFullScreen) { @@ -59,178 +59,178 @@ document.webkitExitFullscreen(); } """) + } + + fun switchFullscreen() { + if (isFullscreen()) { + exitFullscreen() + } else { + requestFullscreen() + } + } + + fun isFullscreen(): Boolean { + val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + + return fse != undefined + } + + fun updateView() { + aspectRatio = windowWidth / windowHeight.toFloat() + + if (aspectRatio < minAspectRatio) { + aspectRatio = minAspectRatio + + windowHeight = (windowWidth / aspectRatio).toInt() } - fun switchFullscreen() { - if (isFullscreen()) { - exitFullscreen() - } else { - requestFullscreen() - } + if (aspectRatio > maxAspectRatio) { + aspectRatio = maxAspectRatio + + windowWidth = (windowHeight * aspectRatio).toInt() } - fun isFullscreen(): Boolean { - val fse = js("document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement"); + when (viewType) { + ViewType.ABSOLUTE -> { + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.WIDTH -> { + height = width / aspectRatio - return fse != undefined + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.HEIGHT -> { + width = height * aspectRatio + + vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) + } + ViewType.PROJECTION -> { + vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun updateView() { - aspectRatio = windowWidth / windowHeight.toFloat() + //println("width: $width, height: $height") + } - if (aspectRatio < minAspectRatio) { - aspectRatio = minAspectRatio + fun screenToGameCoordX(screenX: Float): Float { + var result = screenX - windowHeight = (windowWidth / aspectRatio).toInt() - } - - if (aspectRatio > maxAspectRatio) { - aspectRatio = maxAspectRatio - - windowWidth = (windowHeight * aspectRatio).toInt() - } - - when (viewType) { - ViewType.ABSOLUTE -> { - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.WIDTH -> { - height = width / aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.HEIGHT -> { - width = height * aspectRatio - - vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far) - } - ViewType.PROJECTION -> { - vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far) - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } - - //println("width: $width, height: $height") + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = ((screenX - Game.borderLeft) * width / windowWidth) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordX(screenX: Float): Float { - var result = screenX + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( (screenX - Game.borderLeft) * width / windowWidth ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun screenToGameCoordY(screenY: Float): Float { + var result = screenY - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - ((screenY - Game.borderTop) * height / windowHeight) + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun screenToGameCoordY(screenY: Float): Float { - var result = screenY + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( (screenY - Game.borderTop) * height / windowHeight ) - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordX(gameX: Float): Float { + var result = gameX + val normalizedX = gameX + (width / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = (gameX / width * windowWidth) + Game.borderLeft + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordX(gameX: Float): Float { - var result = gameX - val normalizedX = gameX + (width / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = ( gameX / width * windowWidth ) + Game.borderLeft - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun gameToScreenCoordY(gameY: Float): Float { + var result = gameY + val normalizedY = gameY + (height / 2) - return result + when (viewType) { + ViewType.ABSOLUTE -> { + // nop + } + ViewType.WIDTH, ViewType.HEIGHT -> { + result = height - (gameY / height * windowHeight) + Game.borderTop + } + ViewType.PROJECTION -> { + // uhm + } + else -> { + throw IllegalStateException("ViewType $viewType not implemented!") + } } - fun gameToScreenCoordY(gameY: Float): Float { - var result = gameY - val normalizedY = gameY + (height / 2) + return result + } - when (viewType) { - ViewType.ABSOLUTE -> { - // nop - } - ViewType.WIDTH, ViewType.HEIGHT -> { - result = height - ( gameY / height * windowHeight ) + Game.borderTop - } - ViewType.PROJECTION -> { - // uhm - } - else -> { - throw IllegalStateException("ViewType $viewType not implemented!") - } - } + fun setToWidth(width: Float) { + this.width = width + this.viewType = ViewType.WIDTH - return result - } + updateView() + } - fun setToWidth(width: Float) { - this.width = width - this.viewType = ViewType.WIDTH + fun setToHeight(height: Float) { + this.height = height + this.viewType = ViewType.HEIGHT - updateView() - } + updateView() + } - fun setToHeight(height: Float) { - this.height = height - this.viewType = ViewType.HEIGHT + fun setProjection(angle: Float) { + this.angle = angle + this.viewType = ViewType.PROJECTION - updateView() - } + updateView() + } - fun setProjection(angle: Float) { - this.angle = angle - this.viewType = ViewType.PROJECTION + fun setNear(near: Float) { + this.near = near - updateView() - } + updateView() + } - fun setNear(near: Float) { - this.near = near + fun setFar(far: Float) { + this.far = far - updateView() - } - - fun setFar(far: Float) { - this.far = far - - updateView() - } + updateView() + } } \ No newline at end of file diff --git a/src/main/kotlin/games/perses/input/Input.kt b/src/main/kotlin/games/perses/input/Input.kt index 71a3adc..58c4f23 100644 --- a/src/main/kotlin/games/perses/input/Input.kt +++ b/src/main/kotlin/games/perses/input/Input.kt @@ -15,235 +15,235 @@ */ enum class KeyCode(val keyCode: Int) { - BACKSPACE(8), - TAB(9), - ENTER(13), - SHIFT(16), - CTRL(17), - ALT(18), - PAUSE_BREAK(19), - CAPS_LOCK(20), - ESCAPE(27), - SPACE(32), - PAGE_UP(33), - PAGE_DOWN(34), - END(35), - HOME(36), - LEFT_ARROW(37), - UP_ARROW(38), - RIGHT_ARROW(39), - DOWN_ARROW(40), - INSERT(45), - DELETE(46), - NR_0(48), - NR_1(49), - NR_2(50), - NR_3(51), - NR_4(52), - NR_5(53), - NR_6(54), - NR_7(55), - NR_8(56), - NR_9(57), - A(65), - B(66), - C(67), - D(68), - E(69), - F(70), - G(71), - H(72), - I(73), - J(74), - K(75), - L(76), - M(77), - N(78), - O(79), - P(80), - Q(81), - R(82), - S(83), - T(84), - U(85), - V(86), - W(87), - X(88), - Y(89), - Z(90), - LEFT_WINDOW_KEY(91), - RIGHT_WINDOW_KEY(92), - SELECT_KEY(93), - NUMPAD_0(96), - NUMPAD_1(97), - NUMPAD_2(98), - NUMPAD_3(99), - NUMPAD_4(100), - NUMPAD_5(101), - NUMPAD_6(102), - NUMPAD_7(103), - NUMPAD_8(104), - NUMPAD_9(105), - MULTIPLY(106), - ADD(107), - SUBTRACT(109), - DECIMAL_POINT(110), - DIVIDE(111), - F1(112), - F2(113), - F3(114), - F4(115), - F5(116), - F6(117), - F7(118), - F8(119), - F9(120), - F10(121), - F11(122), - F12(123), - NUM_LOCK(144), - SCROLL_LOCK(145), - SEMI_COLON(186), - EQUAL_SIGN(187), - COMMA(188), - DASH(189), - PERIOD(190), - FORWARD_SLASH(191), - GRAVE_ACCENT(192), - OPEN_BRACKET(219), - BACK_SLASH(220), - CLOSE_BRAKET(221), - SINGLE_QUOTE(222), + BACKSPACE(8), + TAB(9), + ENTER(13), + SHIFT(16), + CTRL(17), + ALT(18), + PAUSE_BREAK(19), + CAPS_LOCK(20), + ESCAPE(27), + SPACE(32), + PAGE_UP(33), + PAGE_DOWN(34), + END(35), + HOME(36), + LEFT_ARROW(37), + UP_ARROW(38), + RIGHT_ARROW(39), + DOWN_ARROW(40), + INSERT(45), + DELETE(46), + NR_0(48), + NR_1(49), + NR_2(50), + NR_3(51), + NR_4(52), + NR_5(53), + NR_6(54), + NR_7(55), + NR_8(56), + NR_9(57), + A(65), + B(66), + C(67), + D(68), + E(69), + F(70), + G(71), + H(72), + I(73), + J(74), + K(75), + L(76), + M(77), + N(78), + O(79), + P(80), + Q(81), + R(82), + S(83), + T(84), + U(85), + V(86), + W(87), + X(88), + Y(89), + Z(90), + LEFT_WINDOW_KEY(91), + RIGHT_WINDOW_KEY(92), + SELECT_KEY(93), + NUMPAD_0(96), + NUMPAD_1(97), + NUMPAD_2(98), + NUMPAD_3(99), + NUMPAD_4(100), + NUMPAD_5(101), + NUMPAD_6(102), + NUMPAD_7(103), + NUMPAD_8(104), + NUMPAD_9(105), + MULTIPLY(106), + ADD(107), + SUBTRACT(109), + DECIMAL_POINT(110), + DIVIDE(111), + F1(112), + F2(113), + F3(114), + F4(115), + F5(116), + F6(117), + F7(118), + F8(119), + F9(120), + F10(121), + F11(122), + F12(123), + NUM_LOCK(144), + SCROLL_LOCK(145), + SEMI_COLON(186), + EQUAL_SIGN(187), + COMMA(188), + DASH(189), + PERIOD(190), + FORWARD_SLASH(191), + GRAVE_ACCENT(192), + OPEN_BRACKET(219), + BACK_SLASH(220), + CLOSE_BRAKET(221), + SINGLE_QUOTE(222), - ESC(27), - LEFT(37), - UP(38), - DOWN(40), - RIGHT(39), - MINUS(109), - PLUS(107), + ESC(27), + LEFT(37), + UP(38), + DOWN(40), + RIGHT(39), + MINUS(109), + PLUS(107), } interface InputProcessor { - fun keyPressed(charCode: Int) + fun keyPressed(charCode: Int) - fun keyDown(keyCode: Int) + fun keyDown(keyCode: Int) - fun keyUp(keyCode: Int) + fun keyUp(keyCode: Int) - fun pointerClick(pointer: Int, x: Float, y: Float) + fun pointerClick(pointer: Int, x: Float, y: Float) - fun mouseMove(x: Float, y: Float) + fun mouseMove(x: Float, y: Float) } open class EmptyInputProcessor : InputProcessor { - override fun pointerClick(pointer: Int, x: Float, y: Float) { } + override fun pointerClick(pointer: Int, x: Float, y: Float) {} - override fun keyDown(keyCode: Int) { } + override fun keyDown(keyCode: Int) {} - override fun keyPressed(charCode: Int) { } + override fun keyPressed(charCode: Int) {} - override fun keyUp(keyCode: Int) { } + override fun keyUp(keyCode: Int) {} - override fun mouseMove(x: Float, y: Float) { } + override fun mouseMove(x: Float, y: Float) {} } object Input { - private val keys: MutableMap = HashMap() - private var inputProcesser: InputProcessor = EmptyInputProcessor() + private val keys: MutableMap = HashMap() + private var inputProcesser: InputProcessor = EmptyInputProcessor() - init { - val body = document.body - if (body != null) { - body.onkeydown = { - keyDown(it) - } + init { + val body = document.body + if (body != null) { + body.onkeydown = { + keyDown(it) + } - body.onkeyup = { - keyUp(it) - } + body.onkeyup = { + keyUp(it) + } - body.onkeypress = { - keyPress(it) - } + body.onkeypress = { + keyPress(it) + } - body.onclick = { - mouseClick(it) - } + body.onclick = { + mouseClick(it) + } - body.onmousedown = { - mouseMove(it) - } + body.onmousedown = { + mouseMove(it) + } - body.onmouseup = { - mouseMove(it) - } + body.onmouseup = { + mouseMove(it) + } - body.onmousemove = { - mouseMove(it) - } - } else { - console.log("Can't register key events, document.body is null!?") - } + body.onmousemove = { + mouseMove(it) + } + } else { + console.log("Can't register key events, document.body is null!?") } + } - fun setInputProcessor(processor: InputProcessor) { - this.inputProcesser = processor + fun setInputProcessor(processor: InputProcessor) { + this.inputProcesser = processor + } + + private fun keyDown(key: Event) { + if (key is KeyboardEvent) { + keys.put(key.keyCode, Date().getTime()) + + inputProcesser.keyDown(key.keyCode) } + } - private fun keyDown(key: Event) { - if (key is KeyboardEvent) { - keys.put(key.keyCode, Date().getTime()) + private fun keyUp(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyUp(key.keyCode) - inputProcesser.keyDown(key.keyCode) - } + keys.remove(key.keyCode) } + } - private fun keyUp(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyUp(key.keyCode) - - keys.remove(key.keyCode) - } + private fun keyPress(key: Event) { + if (key is KeyboardEvent) { + inputProcesser.keyPressed(key.charCode) } + } - private fun keyPress(key: Event) { - if (key is KeyboardEvent) { - inputProcesser.keyPressed(key.charCode) - } + private fun mouseClick(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + + inputProcesser.pointerClick(event.button.toInt(), vx, vy) } + } - private fun mouseClick(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + private fun mouseMove(event: Event) { + if (event is MouseEvent) { + val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) + val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) - inputProcesser.pointerClick(event.button.toInt(), vx, vy) - } + inputProcesser.mouseMove(vx, vy) } + } - private fun mouseMove(event: Event) { - if (event is MouseEvent) { - val vx: Float = Game.view.screenToGameCoordX(event.getX(Game.html.container).toFloat()) - val vy: Float = Game.view.screenToGameCoordY(event.getY(Game.html.container).toFloat()) + fun isDown(keyCode: Int) = keys.containsKey(keyCode) - inputProcesser.mouseMove(vx, vy) - } - } + fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - fun isDown(keyCode: Int) = keys.containsKey(keyCode) + fun wasPressed(keyCode: Int, delta: Double): Boolean { + val time = keys[keyCode] - fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode) - - fun wasPressed(keyCode: Int, delta: Double): Boolean { - val time = keys[keyCode] - - return (time != null && time > (Date().getTime() - delta)) - } + return (time != null && time > (Date().getTime() - delta)) + } } diff --git a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt index f1c7808..f3d4126 100644 --- a/src/main/kotlin/games/perses/map/tiled/TiledMap.kt +++ b/src/main/kotlin/games/perses/map/tiled/TiledMap.kt @@ -11,201 +11,201 @@ */ class MapData { - var version: Int = 1 - var properties: MutableMap = HashMap() - var layers: Array? = null - var tilesets: Array? = null + var version: Int = 1 + var properties: MutableMap = HashMap() + var layers: Array? = null + var tilesets: Array? = null - var height: Int = 0 - var width: Int = 0 + var height: Int = 0 + var width: Int = 0 - var nextobjectid: Int = 0 - var orientation: String = "orthogonal" - var renderorder: String = "right-down" - var tileheight: Int = 0 - var tilewidth: Int = 0 + var nextobjectid: Int = 0 + var orientation: String = "orthogonal" + var renderorder: String = "right-down" + var tileheight: Int = 0 + var tilewidth: Int = 0 } class MapLayer { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var data: Array? = null - var encoding: String = "" - var x: Int = 0 - var y: Int = 0 - var width: Int = 0 - var height: Int = 0 - var name: String = "" - var opacity: Float = 1f - var type: String = "" - var visible: Boolean = true - var draworder: String = "" + var data: Array? = null + var encoding: String = "" + var x: Int = 0 + var y: Int = 0 + var width: Int = 0 + var height: Int = 0 + var name: String = "" + var opacity: Float = 1f + var type: String = "" + var visible: Boolean = true + var draworder: String = "" } class MapTileset { - var properties: MutableMap = HashMap() + var properties: MutableMap = HashMap() - var firstgid: Int = 0 - var image: String = "" - var imageheight: Int = 0 - var imagewidth: Int = 0 - var margin: Int = 0 - var name: String = "" - var spacing: Int = 0 - var tilecount: Int = 0 - var tileheight: Int = 0 - var tilewidth: Int = 0 - var tileproperties: MutableMap> = HashMap() + var firstgid: Int = 0 + var image: String = "" + var imageheight: Int = 0 + var imagewidth: Int = 0 + var margin: Int = 0 + var name: String = "" + var spacing: Int = 0 + var tilecount: Int = 0 + var tileheight: Int = 0 + var tilewidth: Int = 0 + var tileproperties: MutableMap> = HashMap() } class TilesetIndex( - val texture: Texture?, - val tcLeft: Float, - val tcTop: Float, - val tcRight: Float, - val tcBottom: Float, - val scale: Float - ) { - constructor() : this(null, 0f, 0f, 0f, 0f, 0f) + val texture: Texture?, + val tcLeft: Float, + val tcTop: Float, + val tcRight: Float, + val tcBottom: Float, + val scale: Float +) { + constructor() : this(null, 0f, 0f, 0f, 0f, 0f) - fun render(x: Float, y: Float) { - texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) - } + fun render(x: Float, y: Float) { + texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale) + } } class TiledMap(dir: String = "", url: String) { - val properties: Map = HashMap() - val data: MapData - val tileset: Array - val tiles: Array - var first = true - //var tilesetIndex: Array = Array(0, { TilesetIndex() }) + val properties: Map = HashMap() + val data: MapData + val tileset: Array + val tiles: Array + var first = true + //var tilesetIndex: Array = Array(0, { TilesetIndex() }) - init { - var tileDir = dir - if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { - tileDir = tileDir + "/" - } - - data = JSON.parse(getUrlAsString(tileDir + url)) - //println("map data is loaded") - val tilesets = data.tilesets - if (tilesets != null) { - tileset = Array(tilesets.size, { "" }) - var maxGid = 0 - for (index in 0..tilesets.size - 1) { - tileset[index] = tilesets[index].name - Textures.load(tilesets[index].name, tileDir + tilesets[index].image) - maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) - } - - tiles = Array(maxGid, { TilesetIndex() }) - } else { - tileset = Array(0, { "" }) - tiles = Array(0, { TilesetIndex() }) - } - - cacheTiles() + init { + var tileDir = dir + if (!tileDir.isEmpty() && !tileDir.endsWith("/")) { + tileDir = tileDir + "/" } - fun cacheTiles() { - if (!Textures.ready()) { - window.setTimeout({ cacheTiles() }, 10) - } else { - val tilesets = data.tilesets - var tcLeft = 0f - var tcTop = 0f - var tcRight = 0f - var tcBottom = 0f + data = JSON.parse(getUrlAsString(tileDir + url)) + //println("map data is loaded") + val tilesets = data.tilesets + if (tilesets != null) { + tileset = Array(tilesets.size, { "" }) + var maxGid = 0 + for (index in 0..tilesets.size - 1) { + tileset[index] = tilesets[index].name + Textures.load(tilesets[index].name, tileDir + tilesets[index].image) + maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount) + } - if (tilesets != null) { - - - for (tileset in tilesets) { - val tilesHor = tileset.imagewidth / tileset.tilewidth - val tilesVer = tileset.imageheight / tileset.tileheight - val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) - - for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { - val texture = Textures.get(tileset.name) - - val gid = index - tileset.firstgid - - val xi = gid % tilesHor - var yi = gid / tilesHor - yi = tilesVer - yi - 1 - val tw = 1f / tilesHor.toFloat() - val th = 1f / tilesVer.toFloat() - - val pixelW = 0.1f / tileset.tilewidth - val pixelH = 0.1f / tileset.tileheight - - tcLeft = xi * tw - tcRight = tcLeft + tw - - // switch up/down because of texture coord 0,0 in left bottom corner - tcBottom = yi * th - tcTop = tcBottom + th - - tcLeft += pixelW - tcRight -= pixelW - - tcBottom += pixelH - tcTop -= pixelH - - tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) - } - } - } - } + tiles = Array(maxGid, { TilesetIndex() }) + } else { + tileset = Array(0, { "" }) + tiles = Array(0, { TilesetIndex() }) } - fun drawTile(tile: Int, x: Float, y: Float) { - tiles[tile].render(x, y) + cacheTiles() + } + + fun cacheTiles() { + if (!Textures.ready()) { + window.setTimeout({ cacheTiles() }, 10) + } else { + val tilesets = data.tilesets + var tcLeft = 0f + var tcTop = 0f + var tcRight = 0f + var tcBottom = 0f + + if (tilesets != null) { + + + for (tileset in tilesets) { + val tilesHor = tileset.imagewidth / tileset.tilewidth + val tilesVer = tileset.imageheight / tileset.tileheight + val scale = (tileset.tilewidth / tileset.imagewidth.toFloat()) + + for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) { + val texture = Textures.get(tileset.name) + + val gid = index - tileset.firstgid + + val xi = gid % tilesHor + var yi = gid / tilesHor + yi = tilesVer - yi - 1 + val tw = 1f / tilesHor.toFloat() + val th = 1f / tilesVer.toFloat() + + val pixelW = 0.1f / tileset.tilewidth + val pixelH = 0.1f / tileset.tileheight + + tcLeft = xi * tw + tcRight = tcLeft + tw + + // switch up/down because of texture coord 0,0 in left bottom corner + tcBottom = yi * th + tcTop = tcBottom + th + + tcLeft += pixelW + tcRight -= pixelW + + tcBottom += pixelH + tcTop -= pixelH + + tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale) + } + } + } + } + } + + fun drawTile(tile: Int, x: Float, y: Float) { + tiles[tile].render(x, y) + } + + fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { + var x = 0f + var y = 0f + val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") + val layer = layers[layerIndex] + + val layerData = layer.data + if (layerData != null) { + for (index in layerData.indices) { + // todo: determine if in view + // todo: determine tilewidth + //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { + drawTile(layerData[index], xo + x * 128f, yo + y * 128f) + + when (data.renderorder) { + "right-down" -> { + x++ + if (x >= layer.width) { + x = 0f + y-- + } + } + else -> { + throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") + } + } + //} + } } - fun drawLayer(layerIndex: Int, xo: Float, yo: Float) { - var x = 0f - var y = 0f - val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)") - val layer = layers[layerIndex] + val tilesets = data.tilesets + if (tilesets != null) { + for (tileset in tilesets) { + if (Textures.has(tileset.name)) { + val tx = Textures.get(tileset.name) - val layerData = layer.data - if (layerData != null) { - for (index in layerData.indices) { - // todo: determine if in view - // todo: determine tilewidth - //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) { - drawTile(layerData[index], xo + x * 128f, yo + y * 128f) - - when (data.renderorder) { - "right-down" -> { - x++ - if (x >= layer.width) { - x = 0f - y-- - } - } - else -> { - throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this") - } - } - //} - } + tx.render() } - - val tilesets = data.tilesets - if (tilesets != null) { - for (tileset in tilesets) { - if (Textures.has(tileset.name)) { - val tx = Textures.get(tileset.name) - - tx.render() - } - } - } - - - first = false + } } + + + first = false + } } diff --git a/src/main/kotlin/games/perses/math/Matrix4.kt b/src/main/kotlin/games/perses/math/Matrix4.kt index 7da03cd..bd274bf 100644 --- a/src/main/kotlin/games/perses/math/Matrix4.kt +++ b/src/main/kotlin/games/perses/math/Matrix4.kt @@ -10,184 +10,184 @@ */ class Matrix4 { - internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - internal var temp = FloatArray(16) + internal var temp = FloatArray(16) - private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) + private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) - fun get(): FloatArray { - return matrix + fun get(): FloatArray { + return matrix + } + + fun getFloat32Array() = Float32Array(get().toTypedArray()) + + fun set(values: FloatArray) { + if (values.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun getFloat32Array() = Float32Array(get().toTypedArray()) + matrix = values + } - fun set(values: FloatArray) { - if (values.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } + fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { + val r = (angle / 180f * Math.PI).toFloat() + val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() - matrix = values + matrix[0] = f / imageAspectRatio + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + + matrix[4] = 0.0f + matrix[5] = f + matrix[6] = 0.0f + matrix[7] = 0.0f + + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = -(far + near) / (far - near) + matrix[11] = -1.0f + + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = -(2.0f * far * near) / (far - near) + matrix[15] = 0.0f + } + + fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { + matrix[0] = 2f / (right - left) + matrix[1] = 0f + matrix[2] = 0f + matrix[3] = 0f + + matrix[4] = 0f + matrix[5] = 2f / (top - bottom) + matrix[6] = 0f + matrix[7] = 0f + + matrix[8] = 0f + matrix[9] = 0f + matrix[10] = -2f / (far - near) + matrix[11] = 0f + + matrix[12] = -(right + left) / (right - left) + matrix[13] = -(top + bottom) / (top - bottom) + matrix[14] = -(far + near) / (far - near) + matrix[15] = 1f + } + + fun setToIdentity() { + matrix[0] = 1.0f + matrix[1] = 0.0f + matrix[2] = 0.0f + matrix[3] = 0.0f + matrix[4] = 0.0f + matrix[5] = 1.0f + matrix[6] = 0.0f + matrix[7] = 0.0f + matrix[8] = 0.0f + matrix[9] = 0.0f + matrix[10] = 1.0f + matrix[11] = 0.0f + matrix[12] = 0.0f + matrix[13] = 0.0f + matrix[14] = 0.0f + matrix[15] = 1.0f + } + + fun mul(other: Matrix4) { + mul(other.get()) + } + + protected fun mul(other: FloatArray) { + if (other.size != 16) { + throw IllegalArgumentException("Matrix size should be 16!") } - fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) { - val r = (angle / 180f * Math.PI).toFloat() - val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat() + temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] + temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] + temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] + temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] + temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] + temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] + temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] + temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] + temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] + temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] + temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] + temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] + temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] + temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] + temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] + temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - matrix[0] = f / imageAspectRatio - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f + matrix[0] = temp[0] + matrix[1] = temp[1] + matrix[2] = temp[2] + matrix[3] = temp[3] + matrix[4] = temp[4] + matrix[5] = temp[5] + matrix[6] = temp[6] + matrix[7] = temp[7] + matrix[8] = temp[8] + matrix[9] = temp[9] + matrix[10] = temp[10] + matrix[11] = temp[11] + matrix[12] = temp[12] + matrix[13] = temp[13] + matrix[14] = temp[14] + matrix[15] = temp[15] + } - matrix[4] = 0.0f - matrix[5] = f - matrix[6] = 0.0f - matrix[7] = 0.0f + fun translate(x: Float, y: Float, z: Float) { + translateMatrix[12] = x + translateMatrix[13] = y + translateMatrix[14] = z - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = -(far + near) / (far - near) - matrix[11] = -1.0f + mul(translateMatrix) + } - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = -(2.0f * far * near) / (far - near) - matrix[15] = 0.0f - } + fun scale(x: Float, y: Float, z: Float) { + scaleMatrix[0] = x + scaleMatrix[5] = y + scaleMatrix[10] = z - fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) { - matrix[0] = 2f / (right - left) - matrix[1] = 0f - matrix[2] = 0f - matrix[3] = 0f + mul(scaleMatrix) + } - matrix[4] = 0f - matrix[5] = 2f / (top - bottom) - matrix[6] = 0f - matrix[7] = 0f + fun rotateX(angle: Float) { + rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() + rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() + rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() + rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - matrix[8] = 0f - matrix[9] = 0f - matrix[10] = -2f / (far - near) - matrix[11] = 0f + mul(rotateXMatrix) + } - matrix[12] = - (right + left) / (right - left) - matrix[13] = - (top + bottom) / (top - bottom) - matrix[14] = - (far + near) / (far - near) - matrix[15] = 1f - } + fun rotateY(angle: Float) { + rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() + rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() + rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - fun setToIdentity() { - matrix[0] = 1.0f - matrix[1] = 0.0f - matrix[2] = 0.0f - matrix[3] = 0.0f - matrix[4] = 0.0f - matrix[5] = 1.0f - matrix[6] = 0.0f - matrix[7] = 0.0f - matrix[8] = 0.0f - matrix[9] = 0.0f - matrix[10] = 1.0f - matrix[11] = 0.0f - matrix[12] = 0.0f - matrix[13] = 0.0f - matrix[14] = 0.0f - matrix[15] = 1.0f - } + mul(rotateYMatrix) + } - fun mul(other: Matrix4) { - mul(other.get()) - } + fun rotateZ(angle: Float) { + rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() + rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() + rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() + rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - protected fun mul(other: FloatArray) { - if (other.size != 16) { - throw IllegalArgumentException("Matrix size should be 16!") - } - - temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12] - temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13] - temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14] - temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15] - temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12] - temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13] - temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14] - temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15] - temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12] - temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13] - temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14] - temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15] - temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12] - temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13] - temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14] - temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15] - - matrix[0] = temp[0] - matrix[1] = temp[1] - matrix[2] = temp[2] - matrix[3] = temp[3] - matrix[4] = temp[4] - matrix[5] = temp[5] - matrix[6] = temp[6] - matrix[7] = temp[7] - matrix[8] = temp[8] - matrix[9] = temp[9] - matrix[10] = temp[10] - matrix[11] = temp[11] - matrix[12] = temp[12] - matrix[13] = temp[13] - matrix[14] = temp[14] - matrix[15] = temp[15] - } - - fun translate(x: Float, y: Float, z: Float) { - translateMatrix[12] = x - translateMatrix[13] = y - translateMatrix[14] = z - - mul(translateMatrix) - } - - fun scale(x: Float, y: Float, z: Float) { - scaleMatrix[0] = x - scaleMatrix[5] = y - scaleMatrix[10] = z - - mul(scaleMatrix) - } - - fun rotateX(angle: Float) { - rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat() - rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat() - rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat() - rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateXMatrix) - } - - fun rotateY(angle: Float) { - rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat() - rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat() - rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateYMatrix) - } - - fun rotateZ(angle: Float) { - rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat() - rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat() - rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat() - rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat() - - mul(rotateZMatrix) - } + mul(rotateZMatrix) + } } diff --git a/src/main/kotlin/games/perses/net/NetUtils.kt b/src/main/kotlin/games/perses/net/NetUtils.kt index 5b5b820..148b920 100644 --- a/src/main/kotlin/games/perses/net/NetUtils.kt +++ b/src/main/kotlin/games/perses/net/NetUtils.kt @@ -9,10 +9,10 @@ */ fun getUrlAsString(url: String): String { - val req = XMLHttpRequest() + val req = XMLHttpRequest() - req.open("GET", url, false) - req.send(null) + req.open("GET", url, false) + req.send(null) - return req.responseText + return req.responseText } diff --git a/src/main/kotlin/games/perses/shader/ShaderProgram.kt b/src/main/kotlin/games/perses/shader/ShaderProgram.kt index cf07c0f..7dde03a 100644 --- a/src/main/kotlin/games/perses/shader/ShaderProgram.kt +++ b/src/main/kotlin/games/perses/shader/ShaderProgram.kt @@ -1,6 +1,10 @@ package games.perses.shader -import org.khronos.webgl.* +import org.khronos.webgl.Float32Array +import org.khronos.webgl.WebGLBuffer +import org.khronos.webgl.WebGLProgram +import org.khronos.webgl.WebGLRenderingContext +import org.khronos.webgl.WebGLShader /** * User: rnentjes @@ -9,103 +13,125 @@ */ class ShaderProgram( - val webgl: WebGLRenderingContext, - val drawType: Int, - vertexShaderSource: String, - fragmentShaderSource: String, - val vainfo: Array, - val setter: (program: ShaderProgram, data: T) -> Unit) { + val webgl: WebGLRenderingContext, + val drawType: Int, + vertexShaderSource: String, + fragmentShaderSource: String, + val vainfo: Array, + val setter: (program: ShaderProgram, data: T) -> Unit +) { - var shaderProgram: WebGLProgram - var vertex: WebGLShader - var fragment: WebGLShader + var shaderProgram: WebGLProgram + var vertex: WebGLShader + var fragment: WebGLShader - var verticesBlockSize = 0 - var drawLength = 0 + var verticesBlockSize = 0 + var drawLength = 0 - init { - vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER) - fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER) + init { + vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER) + fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER) - shaderProgram = webgl.createProgram() ?: throw IllegalStateException("Unable to request shader program from webgl context!") - webgl.attachShader(shaderProgram, vertex) - webgl.attachShader(shaderProgram, fragment) - webgl.linkProgram(shaderProgram) + shaderProgram = webgl.createProgram() ?: throw IllegalStateException( + "Unable to request shader program from webgl context!" + ) + webgl.attachShader(shaderProgram, vertex) + webgl.attachShader(shaderProgram, fragment) + webgl.linkProgram(shaderProgram) - if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) { - //println(webgl.getProgramInfoLog(shaderProgram)) - throw IllegalStateException("Unable to compile shader program!") - } - - webgl.useProgram(shaderProgram) - - this.verticesBlockSize = 0 - - // set attribute locations... - for (info in vainfo.iterator()) { - info.location = webgl.getAttribLocation(shaderProgram, info.locationName) - info.offset = verticesBlockSize - - verticesBlockSize += info.numElements - //println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}") - } - - when(drawType) { - WebGLRenderingContext.TRIANGLES -> { - drawLength = verticesBlockSize * 3 - } - else -> { - drawLength = verticesBlockSize - } - } - - //println("verticesBlockSize $verticesBlockSize") - - //println("ShaderProgram constructor done") + if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) { + //println(webgl.getProgramInfoLog(shaderProgram)) + throw IllegalStateException("Unable to compile shader program!") } - private fun compileShader(source: String, type: Int): WebGLShader { - val result: WebGLShader = webgl.createShader(type) ?: throw IllegalStateException("Unable to request shader from webgl context!") + webgl.useProgram(shaderProgram) - webgl.shaderSource(result, source) - webgl.compileShader(result) + this.verticesBlockSize = 0 - if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) { - throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}") - } + // set attribute locations... + for (info in vainfo.iterator()) { + info.location = webgl.getAttribLocation(shaderProgram, info.locationName) + info.offset = verticesBlockSize - return result + verticesBlockSize += info.numElements + //println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}") } - fun begin(attribBuffer: WebGLBuffer, userdata: T) { - webgl.useProgram(shaderProgram); - webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); - - // set attribute locations... - for (info in vainfo.iterator()) { - webgl.enableVertexAttribArray(info.location) - webgl.vertexAttribPointer(info.location, info.numElements, WebGLRenderingContext.FLOAT, false, verticesBlockSize * 4, info.offset * 4) - } - - setter(this, userdata) + when (drawType) { + WebGLRenderingContext.TRIANGLES -> { + drawLength = verticesBlockSize * 3 + } + else -> { + drawLength = verticesBlockSize + } } - fun end() { - for (info in vainfo.iterator()) { - webgl.disableVertexAttribArray(info.location); - } - webgl.useProgram(null) + //println("verticesBlockSize $verticesBlockSize") + + //println("ShaderProgram constructor done") + } + + private fun compileShader(source: String, type: Int): WebGLShader { + val result: WebGLShader = webgl.createShader(type) + ?: throw IllegalStateException("Unable to request shader from webgl context!") + + webgl.shaderSource(result, source) + webgl.compileShader(result) + + if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) { + throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}") } - fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location); + return result + } - fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location); + fun begin(attribBuffer: WebGLBuffer, userdata: T) { + webgl.useProgram(shaderProgram); + webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); - fun setUniform1f(location: String, value: Float) { webgl.uniform1f(getUniformLocation(location), value); } - fun setUniform2f(location: String, v1: Float, v2: Float) { webgl.uniform2f(getUniformLocation(location), v1, v2); } - fun setUniform3f(location: String, v1: Float, v2: Float, v3: Float) { webgl.uniform3f(getUniformLocation(location), v1, v2, v3); } - fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); } - fun setUniform1i(location: String, value: Int) { webgl.uniform1i(getUniformLocation(location), value); } - fun setUniformMatrix4fv(location: String, value: Float32Array) { webgl.uniformMatrix4fv(getUniformLocation(location), false, value); } + // set attribute locations... + for (info in vainfo.iterator()) { + webgl.enableVertexAttribArray(info.location) + webgl.vertexAttribPointer( + info.location, + info.numElements, + WebGLRenderingContext.FLOAT, + false, + verticesBlockSize * 4, + info.offset * 4 + ) + } + + setter(this, userdata) + } + + fun end() { + for (info in vainfo.iterator()) { + webgl.disableVertexAttribArray(info.location); + } + webgl.useProgram(null) + } + + fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location); + + fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location); + + fun setUniform1f(location: String, value: Float) { + webgl.uniform1f(getUniformLocation(location), value); } + + fun setUniform2f(location: String, v1: Float, v2: Float) { + webgl.uniform2f(getUniformLocation(location), v1, v2); } + + fun setUniform3f(location: String, v1: Float, v2: Float, v3: Float) { + webgl.uniform3f(getUniformLocation(location), v1, v2, v3); } + + fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { + webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); } + + fun setUniform1i(location: String, value: Int) { + webgl.uniform1i(getUniformLocation(location), value); } + + fun setUniformMatrix4fv(location: String, value: Float32Array) { + webgl.uniformMatrix4fv(getUniformLocation(location), false, value); } } diff --git a/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt b/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt index d9a3908..d65cf7f 100644 --- a/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt +++ b/src/main/kotlin/games/perses/shader/ShaderProgramMesh.kt @@ -11,64 +11,67 @@ * Time: 11:57 */ -class VertextAttributeInfo(val locationName: String, val numElements: Int) { - var location = 0 - var offset = 0 +class VertextAttributeInfo( + val locationName: String, + val numElements: Int +) { + var location = 0 + var offset = 0 } class ShaderProgramMesh( - val shaderProgram: ShaderProgram + val shaderProgram: ShaderProgram ) { - val webgl = shaderProgram.webgl - val data: Float32Array = Float32Array(20000 - (20000 % shaderProgram.drawLength)) - var currentIndex: Int = 0 - val attribBuffer: WebGLBuffer - var counter = 0 + val webgl = shaderProgram.webgl + val data: Float32Array = Float32Array(20000 - (20000 % shaderProgram.drawLength)) + var currentIndex: Int = 0 + val attribBuffer: WebGLBuffer + var counter = 0 - init { - attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!") - webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer) + init { + attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!") + webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer) + } + + fun queue(vararg vertices: Float) { + for (vertice in vertices) { + data[currentIndex++] = vertice } - fun queue(vararg vertices: Float) { - for (vertice in vertices) { - data[currentIndex++] = vertice - } - - if (bufferFull()) { - println("Skipped draw call, to many values!") - currentIndex = 0 - } + if (bufferFull()) { + println("Skipped draw call, to many values!") + currentIndex = 0 } + } - fun queueArray(vertices: Array) { - data.set(vertices, currentIndex) - currentIndex += vertices.size + fun queueArray(vertices: Array) { + data.set(vertices, currentIndex) + currentIndex += vertices.size - if (bufferFull()) { - println("Skipped draw call, to many values!") - currentIndex = 0 - } + if (bufferFull()) { + println("Skipped draw call, to many values!") + currentIndex = 0 } + } - fun remaining() = data.length - currentIndex + fun remaining() = data.length - currentIndex - fun bufferFull() = currentIndex == data.length + fun bufferFull() = currentIndex == data.length - fun render(userdata: T) { - counter++ - if (currentIndex > 0) { - if (currentIndex % shaderProgram.verticesBlockSize != 0) { - throw IllegalStateException("Number of vertices not a multiple of the attribute block size!") - } + fun render(userdata: T) { + counter++ + if (currentIndex > 0) { + if (currentIndex % shaderProgram.verticesBlockSize != 0) { + throw IllegalStateException("Number of vertices not a multiple of the attribute block size!") + } - shaderProgram.begin(attribBuffer, userdata) + shaderProgram.begin(attribBuffer, userdata) - webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW) - webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize)) - currentIndex = 0 + webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW) + webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize)) + currentIndex = 0 - shaderProgram.end() - } + shaderProgram.end() } + } } diff --git a/src/main/kotlin/games/perses/sound/Music.kt b/src/main/kotlin/games/perses/sound/Music.kt index a3fcccc..c5ddadf 100644 --- a/src/main/kotlin/games/perses/sound/Music.kt +++ b/src/main/kotlin/games/perses/sound/Music.kt @@ -10,43 +10,43 @@ */ fun HTMLAudioElement.dispose() { - this.pause() - this.parentNode?.removeChild(this) + this.pause() + this.parentNode?.removeChild(this) } object Music { - val playing: MutableSet = HashSet() + val playing: MutableSet = HashSet() - fun load(url: String): HTMLAudioElement { - val audio = document.createElement("audio") as HTMLAudioElement + fun load(url: String): HTMLAudioElement { + val audio = document.createElement("audio") as HTMLAudioElement - audio.src = url + audio.src = url - return audio - } + return audio + } - fun play(url: String, volume: Double = 0.75, looping: Boolean = false): HTMLAudioElement { - val audio = document.createElement("audio") as HTMLAudioElement + fun play(url: String, volume: Double = 0.75, looping: Boolean = false): HTMLAudioElement { + val audio = document.createElement("audio") as HTMLAudioElement - audio.src = url - audio.volume = volume + audio.src = url + audio.volume = volume + audio.play() + + audio.onended = { + if (looping) { + audio.currentTime = 0.0 audio.play() - - audio.onended = { - if (looping) { - audio.currentTime = 0.0 - audio.play() - } else { - //println("REMOVING: $audio") - audio.parentNode?.removeChild(audio) - playing.remove(audio) - } - } - - return audio + } else { + //println("REMOVING: $audio") + audio.parentNode?.removeChild(audio) + playing.remove(audio) + } } - fun stopAll() { + return audio + } - } + fun stopAll() { + + } } diff --git a/src/main/kotlin/games/perses/sound/Sounds.kt b/src/main/kotlin/games/perses/sound/Sounds.kt index f866817..f00aa06 100644 --- a/src/main/kotlin/games/perses/sound/Sounds.kt +++ b/src/main/kotlin/games/perses/sound/Sounds.kt @@ -9,83 +9,88 @@ * Time: 12:34 */ -class Sound(val name:String, val url: String, val defaultVolume: Double = 0.75, val numberOfChannels: Int) { - var channels: Array = +class Sound( + val name: String, + val url: String, + val defaultVolume: Double = 0.75, + val numberOfChannels: Int +) { + var channels: Array = Array(numberOfChannels, { document.createElement("audio") as HTMLAudioElement }) - var nextChannel: Int = 0 + var nextChannel: Int = 0 - init { - //println("CREATING: $name") + init { + //println("CREATING: $name") - for (audio in channels) { - if (audio != null) { - audio.src = url - audio.pause() - audio.load() - audio.volume = defaultVolume - } - } + for (audio in channels) { + if (audio != null) { + audio.src = url + audio.pause() + audio.load() + audio.volume = defaultVolume + } } + } - fun play(volume: Double = defaultVolume) { - //println("PLAYING: $name - $nextChannel") - channels[nextChannel]?.volume = volume - channels[nextChannel]?.currentTime = 0.0 - channels[nextChannel]?.play() + fun play(volume: Double = defaultVolume) { + //println("PLAYING: $name - $nextChannel") + channels[nextChannel]?.volume = volume + channels[nextChannel]?.currentTime = 0.0 + channels[nextChannel]?.play() - nextChannel = (nextChannel + 1) % channels.size + nextChannel = (nextChannel + 1) % channels.size + } + + fun pause() { + for (audio in channels) { + audio?.pause() } + } - fun pause() { - for (audio in channels) { - audio?.pause() - } + fun dispose() { + for (audio in channels) { + audio?.dispose() } - - fun dispose() { - for (audio in channels) { - audio?.dispose() - } - } + } } object Sounds { - val sounds: MutableMap = HashMap() + val sounds: MutableMap = HashMap() - fun load(name: String, url: String, volume: Double = 0.75, channels: Int = 1 ) { - sounds.put(name, Sound(name, url, volume, channels)) + fun load(name: String, url: String, volume: Double = 0.75, channels: Int = 1) { + sounds.put(name, Sound(name, url, volume, channels)) + } + + fun play(name: String, volume: Double? = null) { + val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!") + + if (volume != null) { + sound.play(volume) + } else { + sound.play() + } + } + + fun pause(name: String) { + val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!") + + sound.pause() + } + + fun dispose(name: String) { + val sound: Sound? = sounds[name] + + if (sound != null) { + sounds.remove(name) + sound.dispose() + } + } + + fun disposeAll() { + for (sound in sounds.values) { + sound.dispose() } - fun play(name: String, volume: Double? = null) { - val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!") - - if (volume != null) { - sound.play(volume) - } else { - sound.play() - } - } - - fun pause(name: String) { - val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!") - - sound.pause() - } - - fun dispose(name: String) { - val sound: Sound? = sounds[name] - - if (sound != null) { - sounds.remove(name) - sound.dispose() - } - } - - fun disposeAll() { - for (sound in sounds.values) { - sound.dispose() - } - - sounds.clear() - } + sounds.clear() + } } diff --git a/src/main/kotlin/games/perses/sprite/SpriteBatch.kt b/src/main/kotlin/games/perses/sprite/SpriteBatch.kt index 3de1163..f0b4557 100644 --- a/src/main/kotlin/games/perses/sprite/SpriteBatch.kt +++ b/src/main/kotlin/games/perses/sprite/SpriteBatch.kt @@ -10,17 +10,17 @@ */ class Sprite(val textureName: String) { - val texture: Texture by lazy { Textures.get(textureName) } + val texture: Texture by lazy { Textures[textureName] } } class SpriteBatch { - fun draw(sprite: Sprite, x: Float, y: Float, scale: Float = 1f, rotation: Float = 0f) { - sprite.texture.queueDraw(x, y, scale, rotation) - } + fun draw(sprite: Sprite, x: Float, y: Float, scale: Float = 1f, rotation: Float = 0f) { + sprite.texture.queueDraw(x, y, scale, rotation) + } - fun render() { - Textures.render() - } + fun render() { + Textures.render() + } } diff --git a/src/main/kotlin/games/perses/text/Texts.kt b/src/main/kotlin/games/perses/text/Texts.kt index 52d1a0d..7c71073 100644 --- a/src/main/kotlin/games/perses/text/Texts.kt +++ b/src/main/kotlin/games/perses/text/Texts.kt @@ -7,31 +7,43 @@ */ object Texts { - // TODO: use same coords for webgl and canvas 2d - fun drawText(x: Float, y: Float, message: String, font: String = "bold 24pt Arial", fillStyle: String = "white") { - var yy = y - var xx = x - if (yy < 0) { - yy += Game.view.height - } - if (xx < 0) { - xx += Game.view.width - } - yy = Game.view.height - yy - - Game.html.canvas2d.fillStyle = fillStyle - Game.html.canvas2d.font = font - Game.html.canvas2d.fillText(message, x.toDouble(), yy.toDouble()) + // TODO: use same coords for webgl and canvas 2d + fun drawText( + x: Float, + y: Float, + message: String, + font: String = "bold 24pt Arial", + fillStyle: String = "white" + ) { + var yy = y + var xx = x + if (yy < 0) { + yy += Game.view.height } - - fun drawLeftTop(left: Float, top: Float, message: String, font: String = "bold 24pt Arial", fillStyle: String = "white") { - drawText( - left, - /* Game.view.height - */ top, - message, - font, - fillStyle - ) + if (xx < 0) { + xx += Game.view.width } + yy = Game.view.height - yy + + Game.html.canvas2d.fillStyle = fillStyle + Game.html.canvas2d.font = font + Game.html.canvas2d.fillText(message, x.toDouble(), yy.toDouble()) + } + + fun drawLeftTop( + left: Float, + top: Float, + message: String, + font: String = "bold 24pt Arial", + fillStyle: String = "white" + ) { + drawText( + left, + /* Game.view.height - */ top, + message, + font, + fillStyle + ) + } } diff --git a/src/main/kotlin/games/perses/texture/Textures.kt b/src/main/kotlin/games/perses/texture/Textures.kt index 9053d1f..3ba0203 100644 --- a/src/main/kotlin/games/perses/texture/Textures.kt +++ b/src/main/kotlin/games/perses/texture/Textures.kt @@ -72,78 +72,95 @@ """ class TextureData( - val vMatrix: Matrix4, - val texture: WebGLTexture + val vMatrix: Matrix4, + val texture: WebGLTexture ) class Texture( - val glTexture: WebGLTexture, - shaderProgram: ShaderProgram, - val width: Int, - val height: Int + val glTexture: WebGLTexture, + shaderProgram: ShaderProgram, + val width: Int, + val height: Int ) { - val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram) - val left = -width / 2f - val right = width / 2f - val bottom = -height / 2f - val top = height / 2f + val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram) + val left = -width / 2f + val right = width / 2f + val bottom = -height / 2f + val top = height / 2f - fun queueDraw(x: Float, y: Float, scale: Float = 1f, rotation: Float = 0f) { - shaderProgramMesh.queueArray(arrayOf(x, y, left, bottom, 0f, 0f, scale, rotation)) - shaderProgramMesh.queueArray(arrayOf(x, y, left, top, 0f, 1f, scale, rotation)) - shaderProgramMesh.queueArray(arrayOf(x, y, right, top, 1f, 1f, scale, rotation)) - shaderProgramMesh.queueArray(arrayOf(x, y, right, top, 1f, 1f, scale, rotation)) - shaderProgramMesh.queueArray(arrayOf(x, y, right, bottom, 1f, 0f, scale, rotation)) - shaderProgramMesh.queueArray(arrayOf(x, y, left, bottom, 0f, 0f, scale, rotation)) + fun queueDraw(x: Float, y: Float, scale: Float = 1f, rotation: Float = 0f) { + shaderProgramMesh.queueArray(arrayOf(x, y, left, bottom, 0f, 0f, scale, rotation)) + shaderProgramMesh.queueArray(arrayOf(x, y, left, top, 0f, 1f, scale, rotation)) + shaderProgramMesh.queueArray(arrayOf(x, y, right, top, 1f, 1f, scale, rotation)) + shaderProgramMesh.queueArray(arrayOf(x, y, right, top, 1f, 1f, scale, rotation)) + shaderProgramMesh.queueArray(arrayOf(x, y, right, bottom, 1f, 0f, scale, rotation)) + shaderProgramMesh.queueArray(arrayOf(x, y, left, bottom, 0f, 0f, scale, rotation)) - if (shaderProgramMesh.remaining() < 36) { - render() - } + if (shaderProgramMesh.remaining() < 36) { + render() } + } - fun queueTileDraw(x: Float, y: Float, tcLeft: Float, tcTop: Float, tcRight: Float, tcBottom: Float, scale: Float = 1f, rotation: Float = 0f) { - shaderProgramMesh.queueArray(arrayOf(x, y, left, bottom, tcLeft, tcBottom, scale, rotation)) - shaderProgramMesh.queueArray(arrayOf(x, y, left, top, tcLeft, tcTop, scale, rotation)) - shaderProgramMesh.queueArray(arrayOf(x, y, right, top, tcRight, tcTop, scale, rotation)) - shaderProgramMesh.queueArray(arrayOf(x, y, right, top, tcRight, tcTop, scale, rotation)) - shaderProgramMesh.queueArray(arrayOf(x, y, right, bottom, tcRight, tcBottom, scale, rotation)) - shaderProgramMesh.queueArray(arrayOf(x, y, left, bottom, tcLeft, tcBottom, scale, rotation)) + fun queueTileDraw( + x: Float, + y: Float, + tcLeft: Float, + tcTop: Float, + tcRight: Float, + tcBottom: Float, + scale: Float = 1f, + rotation: Float = 0f + ) { + shaderProgramMesh.queueArray(arrayOf(x, y, left, bottom, tcLeft, tcBottom, scale, rotation)) + shaderProgramMesh.queueArray(arrayOf(x, y, left, top, tcLeft, tcTop, scale, rotation)) + shaderProgramMesh.queueArray(arrayOf(x, y, right, top, tcRight, tcTop, scale, rotation)) + shaderProgramMesh.queueArray(arrayOf(x, y, right, top, tcRight, tcTop, scale, rotation)) + shaderProgramMesh.queueArray(arrayOf(x, y, right, bottom, tcRight, tcBottom, scale, rotation)) + shaderProgramMesh.queueArray(arrayOf(x, y, left, bottom, tcLeft, tcBottom, scale, rotation)) - if (shaderProgramMesh.remaining() < 36) { - render() - } + if (shaderProgramMesh.remaining() < 36) { + render() } + } - fun queueTileDraw(x: Float, y: Float, horCount: Int, verCount: Int, frame: Int, scale: Float = 1f, rotation: Float = 0f) { - val tcw = 1f / horCount - val tch = 1f / verCount + fun queueTileDraw( + x: Float, + y: Float, + horCount: Int, + verCount: Int, + frame: Int, + scale: Float = 1f, + rotation: Float = 0f + ) { + val tcw = 1f / horCount + val tch = 1f / verCount - val tcx = frame % horCount * tcw - val tcy = 1f - (frame / horCount * tch) + val tcx = frame % horCount * tcw + val tcy = 1f - (frame / horCount * tch) - val left = -(width / horCount) / 2f - val right = (width / horCount) / 2f - val bottom = -(height / verCount) / 2f - val top = (height / verCount) / 2f + val left = -(width / horCount) / 2f + val right = (width / horCount) / 2f + val bottom = -(height / verCount) / 2f + val top = (height / verCount) / 2f - shaderProgramMesh.queue( x, y, left, bottom, tcx, tcy - tch, scale, rotation) - shaderProgramMesh.queue( x, y, left, top, tcx, tcy, scale, rotation) - shaderProgramMesh.queue( x, y, right, top, tcx + tcw, tcy, scale, rotation) - shaderProgramMesh.queue( x, y, right, top, tcx + tcw, tcy, scale, rotation) - shaderProgramMesh.queue( x, y, right, bottom, tcx + tcw, tcy - tch, scale, rotation) - shaderProgramMesh.queue( x, y, left, bottom, tcx, tcy - tch, scale, rotation) + shaderProgramMesh.queue(x, y, left, bottom, tcx, tcy - tch, scale, rotation) + shaderProgramMesh.queue(x, y, left, top, tcx, tcy, scale, rotation) + shaderProgramMesh.queue(x, y, right, top, tcx + tcw, tcy, scale, rotation) + shaderProgramMesh.queue(x, y, right, top, tcx + tcw, tcy, scale, rotation) + shaderProgramMesh.queue(x, y, right, bottom, tcx + tcw, tcy - tch, scale, rotation) + shaderProgramMesh.queue(x, y, left, bottom, tcx, tcy - tch, scale, rotation) - if (shaderProgramMesh.remaining() < 36) { - render() - } + if (shaderProgramMesh.remaining() < 36) { + render() } + } - fun render() { - Game.gl().activeTexture(WebGLRenderingContext.TEXTURE0) - Game.gl().bindTexture(WebGLRenderingContext.TEXTURE_2D, glTexture) + fun render() { + Game.gl().activeTexture(WebGLRenderingContext.TEXTURE0) + Game.gl().bindTexture(WebGLRenderingContext.TEXTURE_2D, glTexture) - shaderProgramMesh.render(TextureData(Game.view.vMatrix, glTexture)) - } + shaderProgramMesh.render(TextureData(Game.view.vMatrix, glTexture)) + } } /* @@ -162,170 +179,220 @@ class Pivot(val x: Double, val y: Double) class SpriteSheetData( - val frame: Rect, - val rotated: Boolean, - val trimmed: Boolean, - val spriteSourceSize: Rect, - val sourceSize: Size, - val pivot: Pivot - ) + val frame: Rect, + val rotated: Boolean, + val trimmed: Boolean, + val spriteSourceSize: Rect, + val sourceSize: Size, + val pivot: Pivot +) class SpriteSheet( - val glTexture: WebGLTexture, - val shaderProgram: ShaderProgram, - val data: Map + val glTexture: WebGLTexture, + val shaderProgram: ShaderProgram, + val data: Map ) { } object Textures { - var textures = HashMap() - var startedLoading = 0 - var loaded = 0 - val shaderProgram: ShaderProgram + var textures = HashMap() + var startedLoading = 0 + var loaded = 0 + val shaderProgram: ShaderProgram - init { - val setter = { program: ShaderProgram, data: TextureData -> - program.setUniform1i("u_sampler", 0) - program.setUniformMatrix4fv("u_projectionView", Game.view.vMatrix.getFloat32Array()) - } - - val vainfo = arrayOf( - VertextAttributeInfo("a_position", 2), - VertextAttributeInfo("a_boundingBox", 2), - VertextAttributeInfo("a_texCoord", 2), - VertextAttributeInfo("a_scale", 1), - VertextAttributeInfo("a_rotation", 1) - ) - - shaderProgram = ShaderProgram(Game.gl(), WebGLRenderingContext.Companion.TRIANGLES, vertexShaderSource, fragmentShaderSource, vainfo, setter) + init { + val setter = { program: ShaderProgram, data: TextureData -> + program.setUniform1i("u_sampler", 0) + program.setUniformMatrix4fv("u_projectionView", Game.view.vMatrix.getFloat32Array()) } - fun loadSpriteSheet(name: String) { - //val data = Request(name).json() + val vainfo = arrayOf( + VertextAttributeInfo("a_position", 2), + VertextAttributeInfo("a_boundingBox", 2), + VertextAttributeInfo("a_texCoord", 2), + VertextAttributeInfo("a_scale", 1), + VertextAttributeInfo("a_rotation", 1) + ) - //println(data) + shaderProgram = ShaderProgram( + Game.gl(), + WebGLRenderingContext.Companion.TRIANGLES, + vertexShaderSource, + fragmentShaderSource, + vainfo, + setter + ) + } + + fun loadSpriteSheet(name: String) { + //val data = Request(name).json() + + //println(data) + } + + fun load(name: String, filename: String) { + val gl = Game.gl() + + startedLoading++ + + val webGlTexture = gl.createTexture() + if (webGlTexture != null) { + val image = document.createElement("img") as HTMLImageElement + image.onload = { + textureLoaded(webGlTexture, image) + val texture = Texture(webGlTexture, shaderProgram, image.width, image.height) + + textures.put(name, texture) + + loaded++ + //println("loaded texture $loaded/$startedLoading ${ready()}") + } + image.src = filename + } else { + throw IllegalStateException("Couldn't create webgl texture!") + } + } + + fun create(name: String, image: HTMLImageElement) { + val gl = Game.gl() + + startedLoading++ + + val webGlTexture = gl.createTexture() + if (webGlTexture != null) { + textureLoaded(webGlTexture, image) + val texture = Texture(webGlTexture, shaderProgram, image.width, image.height) + + textures.put(name, texture) + + loaded++ + } else { + throw IllegalStateException("Couldn't create webgl texture!") + } + } + + + fun create(name: String, width: Int, height: Int, image: ArrayBufferView) { + val gl = Game.gl() + + startedLoading++ + + val webGlTexture = gl.createTexture() + if (webGlTexture != null) { + textureLoaded(webGlTexture, width, height, image) + val texture = Texture(webGlTexture, shaderProgram, width, height) + + textures.put(name, texture) + + loaded++ + } else { + throw IllegalStateException("Couldn't create webgl texture!") + } + } + + fun load(mapTileSet: MapTileset) { + + } + + private fun textureLoaded(texture: WebGLTexture, image: HTMLImageElement) { + val gl = Game.gl() + + gl.bindTexture(WebGLRenderingContext.TEXTURE_2D, texture) + gl.pixelStorei(WebGLRenderingContext.UNPACK_FLIP_Y_WEBGL, 1) // second argument must be an int + gl.texImage2D( + WebGLRenderingContext.TEXTURE_2D, + 0, + WebGLRenderingContext.RGBA, + WebGLRenderingContext.RGBA, + WebGLRenderingContext.UNSIGNED_BYTE, + image + ) + setTextureParameters(); + gl.bindTexture(WebGLRenderingContext.TEXTURE_2D, null) + } + + private fun textureLoaded(texture: WebGLTexture, width: Int, height: Int, image: ArrayBufferView) { + val gl = Game.gl() + + gl.bindTexture(WebGLRenderingContext.TEXTURE_2D, texture) + gl.pixelStorei(WebGLRenderingContext.UNPACK_FLIP_Y_WEBGL, 1) // second argument must be an int + gl.texImage2D( + WebGLRenderingContext.TEXTURE_2D, + 0, + WebGLRenderingContext.RGBA, + width, + height, + 0, + WebGLRenderingContext.RGBA, + WebGLRenderingContext.UNSIGNED_BYTE, + image + ) + setTextureParameters(); + gl.bindTexture(WebGLRenderingContext.TEXTURE_2D, null) + } + + private fun setTextureParameters() { + val gl = Game.gl() + + if (Game.view.drawMode == DrawMode.NEAREST) { + gl.texParameteri( + WebGLRenderingContext.TEXTURE_2D, + WebGLRenderingContext.TEXTURE_MAG_FILTER, + WebGLRenderingContext.NEAREST + ) + gl.texParameteri( + WebGLRenderingContext.TEXTURE_2D, + WebGLRenderingContext.TEXTURE_MIN_FILTER, + WebGLRenderingContext.NEAREST + ) + } else { + gl.texParameteri( + WebGLRenderingContext.TEXTURE_2D, + WebGLRenderingContext.TEXTURE_MAG_FILTER, + WebGLRenderingContext.LINEAR + ) + gl.texParameteri( + WebGLRenderingContext.TEXTURE_2D, + WebGLRenderingContext.TEXTURE_MIN_FILTER, + WebGLRenderingContext.LINEAR + ) + } + gl.texParameteri( + WebGLRenderingContext.TEXTURE_2D, + WebGLRenderingContext.TEXTURE_WRAP_T, + WebGLRenderingContext.CLAMP_TO_EDGE + ) + gl.texParameteri( + WebGLRenderingContext.TEXTURE_2D, + WebGLRenderingContext.TEXTURE_WRAP_S, + WebGLRenderingContext.CLAMP_TO_EDGE + ) + } + + fun ready() = loaded == startedLoading + + fun has(name: String) = textures[name] != null + operator fun get(name: String) = textures[name] ?: throw IllegalArgumentException( + "Texture with name $name is not loaded!" + ) + + fun render() { + for ((key, value) in textures) { + value.render() + } + } + + fun dispose() { + val gl = Game.gl() + + for (texture in textures.values) { + gl.deleteTexture(texture.glTexture) } - fun load(name: String, filename: String) { - val gl = Game.gl() - - startedLoading++ - - val webGlTexture = gl.createTexture() - if (webGlTexture != null) { - val image = document.createElement("img") as HTMLImageElement - image.onload = { - textureLoaded(webGlTexture, image) - val texture = Texture(webGlTexture, shaderProgram, image.width, image.height) - - textures.put(name, texture) - - loaded++ - //println("loaded texture $loaded/$startedLoading ${ready()}") - } - image.src = filename - } else { - throw IllegalStateException("Couldn't create webgl texture!") - } - } - - fun create(name: String, image: HTMLImageElement) { - val gl = Game.gl() - - startedLoading++ - - val webGlTexture = gl.createTexture() - if (webGlTexture != null) { - textureLoaded(webGlTexture, image) - val texture = Texture(webGlTexture, shaderProgram, image.width, image.height) - - textures.put(name, texture) - - loaded++ - } else { - throw IllegalStateException("Couldn't create webgl texture!") - } - } - - - fun create(name: String, width: Int, height: Int, image: ArrayBufferView) { - val gl = Game.gl() - - startedLoading++ - - val webGlTexture = gl.createTexture() - if (webGlTexture != null) { - textureLoaded(webGlTexture, width, height, image) - val texture = Texture(webGlTexture, shaderProgram, width, height) - - textures.put(name, texture) - - loaded++ - } else { - throw IllegalStateException("Couldn't create webgl texture!") - } - } - - fun load(mapTileSet: MapTileset) { - - } - - private fun textureLoaded(texture: WebGLTexture, image: HTMLImageElement) { - val gl = Game.gl() - - gl.bindTexture(WebGLRenderingContext.TEXTURE_2D, texture) - gl.pixelStorei(WebGLRenderingContext.UNPACK_FLIP_Y_WEBGL, 1) // second argument must be an int - gl.texImage2D(WebGLRenderingContext.TEXTURE_2D, 0, WebGLRenderingContext.RGBA, WebGLRenderingContext.RGBA, WebGLRenderingContext.UNSIGNED_BYTE, image) - setTextureParameters(); - gl.bindTexture(WebGLRenderingContext.TEXTURE_2D, null) - } - - private fun textureLoaded(texture: WebGLTexture, width: Int, height: Int, image: ArrayBufferView) { - val gl = Game.gl() - - gl.bindTexture(WebGLRenderingContext.TEXTURE_2D, texture) - gl.pixelStorei(WebGLRenderingContext.UNPACK_FLIP_Y_WEBGL, 1) // second argument must be an int - gl.texImage2D(WebGLRenderingContext.TEXTURE_2D, 0, WebGLRenderingContext.RGBA, width, height, 0, WebGLRenderingContext.RGBA, WebGLRenderingContext.UNSIGNED_BYTE, image) - setTextureParameters(); - gl.bindTexture(WebGLRenderingContext.TEXTURE_2D, null) - } - - private fun setTextureParameters() { - val gl = Game.gl() - - if (Game.view.drawMode == DrawMode.NEAREST) { - gl.texParameteri(WebGLRenderingContext.TEXTURE_2D, WebGLRenderingContext.TEXTURE_MAG_FILTER, WebGLRenderingContext.NEAREST) - gl.texParameteri(WebGLRenderingContext.TEXTURE_2D, WebGLRenderingContext.TEXTURE_MIN_FILTER, WebGLRenderingContext.NEAREST) - } else { - gl.texParameteri(WebGLRenderingContext.TEXTURE_2D, WebGLRenderingContext.TEXTURE_MAG_FILTER, WebGLRenderingContext.LINEAR) - gl.texParameteri(WebGLRenderingContext.TEXTURE_2D, WebGLRenderingContext.TEXTURE_MIN_FILTER, WebGLRenderingContext.LINEAR) - } - gl.texParameteri(WebGLRenderingContext.TEXTURE_2D, WebGLRenderingContext.TEXTURE_WRAP_T, WebGLRenderingContext.CLAMP_TO_EDGE) - gl.texParameteri(WebGLRenderingContext.TEXTURE_2D, WebGLRenderingContext.TEXTURE_WRAP_S, WebGLRenderingContext.CLAMP_TO_EDGE) - } - - fun ready() = loaded == startedLoading - - fun has(name: String) = textures[name] != null - operator fun get(name: String) = textures[name] ?: throw IllegalArgumentException("Texture with name $name is not loaded!") - - fun render() { - for ((key, value) in textures) { - value.render() - } - } - - fun dispose() { - val gl = Game.gl() - - for (texture in textures.values) { - gl.deleteTexture(texture.glTexture) - } - - startedLoading = 0 - loaded = 0 - textures.clear() - } + startedLoading = 0 + loaded = 0 + textures.clear() + } }