commit 292619749a9d472a7db1dce939c82d80861a1e4b Author: Gnarwhal Date: Wed Aug 7 04:58:40 2024 +0000 Entire project diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f0be21d --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +bin/ +.settings/ +*.jar +*.zip +*.bat +.project +.classpath +*.txt diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e129676 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +Mit License + +Copyright (c) 2018 Gnarly Narwhal + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a16492f --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# Ludum Dare 40 + +## Getting Started + +### Prerequisites +Must have [Java](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) installed +* NOTE: I run Java 9 so I cannot guarantee that it will work on earlier version, but I don't believe I've used anything preventing it from running on some older versions. Click [here](http://www.oracle.com/technetwork/java/javase/downloads/jdk9-downloads-3848520.html) to download Java 9. + +Graphics driver must have support for OpenGL 3.3 Core or later + +### What's this all about? +This project is my game for Ludum Dare 40. If you don't know what [Ludum Dare](https://ldjam.com/about) is and you're into making games then definitely check it out [here](https://ldjam.com/about). + +### So what's the game? +The game is a snake inspired game in which you control a snake and navigate though levels to reach the end. + +### Can I play it? +Of course! Here's how: + +Click [here](https://drive.google.com/drive/folders/1CPgHTXhfeaYPd9OUWtnpnup5hiO7CTq2?usp=sharing) to download the game. Once you've downloaded it extract the zip file and run the jar file. + +Of course you can always download the source and compile it yourself. You are going to need [LWJGL 3](https://www.lwjgl.org/download). Make sure to include JOML under **Addons** diff --git a/res/audio/chiptune1.wav b/res/audio/chiptune1.wav new file mode 100644 index 0000000..b958f3b Binary files /dev/null and b/res/audio/chiptune1.wav differ diff --git a/res/audio/chiptune2.wav b/res/audio/chiptune2.wav new file mode 100644 index 0000000..678ffac Binary files /dev/null and b/res/audio/chiptune2.wav differ diff --git a/res/audio/fretnoise.wav b/res/audio/fretnoise.wav new file mode 100644 index 0000000..d75d054 Binary files /dev/null and b/res/audio/fretnoise.wav differ diff --git a/res/audio/medieval.wav b/res/audio/medieval.wav new file mode 100644 index 0000000..bcdb921 Binary files /dev/null and b/res/audio/medieval.wav differ diff --git a/res/audio/medievalharp.wav b/res/audio/medievalharp.wav new file mode 100644 index 0000000..99c9ee7 Binary files /dev/null and b/res/audio/medievalharp.wav differ diff --git a/res/audio/medievalsynth.wav b/res/audio/medievalsynth.wav new file mode 100644 index 0000000..0ef320a Binary files /dev/null and b/res/audio/medievalsynth.wav differ diff --git a/res/audio/menu.wav b/res/audio/menu.wav new file mode 100644 index 0000000..9dfdfee Binary files /dev/null and b/res/audio/menu.wav differ diff --git a/res/audio/samples.ceol b/res/audio/samples.ceol new file mode 100644 index 0000000..981cb84 --- /dev/null +++ b/res/audio/samples.ceol @@ -0,0 +1 @@ +3,0,0,0,80,16,4,11,120,0,0,128,0,256,32,0,2,128,0,256,363,1,20,128,0,199,130,0,2,128,0,256,363,1,20,128,0,150,134,0,1,102,1,256,307,0,2,128,0,256,140,0,20,40,0,256,141,0,20,128,0,125,133,0,0,128,0,164,134,0,1,128,0,256,67,0,0,0,0,12,43,2,0,0,43,2,2,0,41,1,4,0,43,2,5,0,38,2,7,0,36,1,9,0,38,1,10,0,36,1,11,0,38,1,12,0,36,1,13,0,34,1,14,0,31,1,15,0,0,0,0,0,0,11,36,2,0,0,36,2,2,0,36,1,4,0,38,2,5,0,41,2,7,0,41,1,9,0,38,1,10,0,36,2,11,0,34,1,13,0,31,1,14,0,29,1,15,0,0,0,0,0,0,10,31,2,0,0,31,2,2,0,31,1,4,0,34,1,5,0,38,1,6,0,43,3,7,0,45,1,10,0,43,3,11,0,46,1,14,0,45,1,15,0,0,0,0,1,2,12,38,1,11,0,36,1,12,0,31,1,14,0,29,1,15,0,36,1,6,0,38,1,9,0,38,1,10,0,34,1,13,0,38,2,7,0,31,2,2,0,34,2,4,0,43,2,0,0,0,0,0,1,2,11,31,2,0,0,34,2,2,0,36,2,4,0,38,1,6,0,43,1,13,0,41,2,7,0,41,1,9,0,41,1,10,0,43,2,11,0,46,1,14,0,50,1,15,0,0,0,0,1,2,12,55,2,0,0,53,1,2,0,50,2,3,0,48,1,5,0,46,2,6,0,43,1,8,0,41,2,9,0,38,1,11,0,36,1,12,0,34,1,13,0,31,1,14,0,29,1,15,0,0,0,0,1,2,11,31,1,0,0,31,1,2,0,34,1,4,0,38,2,7,0,41,1,9,0,38,1,10,0,41,1,15,0,38,2,11,0,41,1,13,0,43,1,14,0,36,2,5,0,0,0,0,2,20,27,0,2,0,0,0,2,2,0,0,1,4,0,0,2,5,0,0,2,7,0,0,1,9,0,0,2,10,0,0,1,12,0,0,1,15,0,0,1,13,0,0,1,14,0,1,2,2,0,1,2,5,0,1,2,8,0,1,2,11,0,1,2,14,0,5,1,0,0,5,1,2,0,5,1,5,0,5,2,7,0,5,1,9,0,5,1,4,0,5,1,13,0,5,1,14,0,5,1,10,0,5,1,11,0,5,1,15,0,0,0,0,1,2,13,43,2,0,0,43,1,2,0,43,2,3,0,41,1,5,0,43,1,6,0,48,1,15,0,46,2,7,0,43,1,9,0,41,1,10,0,38,1,11,0,41,1,12,0,43,1,13,0,46,1,14,0,0,0,0,1,2,13,50,1,0,0,50,1,3,0,50,1,1,0,48,2,4,0,50,1,6,0,45,2,7,0,29,1,15,0,31,1,14,0,34,1,13,0,36,1,12,0,43,1,9,0,41,1,10,0,38,1,11,0,0,0,0,3,2,5,46,4,4,0,43,4,0,0,43,4,8,0,38,2,12,0,41,2,14,0,0,0,0,3,2,4,43,4,0,0,46,4,4,0,50,4,8,0,50,2,14,0,0,0,0,3,2,4,48,4,4,0,46,4,12,0,50,4,8,0,51,4,0,0,0,0,0,3,2,8,48,2,0,0,46,1,2,0,45,1,3,0,41,2,4,0,41,2,14,0,38,2,12,0,43,2,6,0,43,4,8,0,0,0,0,4,20,12,5,2,8,0,5,2,10,0,5,2,0,0,5,2,2,0,4,4,4,0,4,4,12,0,1,2,8,0,1,2,4,0,1,2,0,0,1,2,12,0,1,2,2,0,1,2,10,0,0,0,0,5,1,8,62,4,2,0,58,5,1,0,55,6,0,0,61,2,6,0,62,2,8,0,60,4,12,0,53,4,12,0,56,4,12,0,0,0,0,5,1,14,54,2,6,0,61,2,6,0,58,2,0,0,62,2,0,0,55,2,0,0,55,4,2,0,58,4,2,0,62,4,2,0,58,4,12,0,51,4,12,0,55,4,12,0,62,2,8,0,58,2,8,0,55,2,8,0,0,0,0,6,2,7,55,2,14,0,57,2,4,0,50,4,0,0,50,4,6,0,57,2,10,0,53,1,12,0,53,1,13,0,0,0,0,6,2,7,52,2,0,0,52,2,12,0,48,2,14,0,48,2,2,0,45,2,4,0,50,4,6,0,53,2,10,0,0,0,0,6,2,5,57,2,10,0,62,2,14,0,50,2,2,0,50,6,4,0,45,2,0,0,0,0,0,6,2,8,67,2,0,0,69,2,2,0,65,1,4,0,65,1,5,0,64,2,6,0,62,2,8,0,60,2,10,0,65,4,12,0,0,0,0,6,2,8,64,2,0,0,64,2,6,0,67,2,10,0,64,2,12,0,62,2,14,0,65,1,8,0,65,1,9,0,65,4,2,0,0,0,0,6,2,6,60,2,0,0,74,2,6,0,74,2,12,0,62,4,8,0,62,4,14,0,62,4,2,0,0,0,0,6,2,7,74,2,2,0,62,1,4,0,62,1,5,0,60,2,10,0,62,2,12,0,65,2,14,0,62,4,6,0,0,0,0,6,2,8,69,4,0,0,74,2,8,0,69,2,10,0,72,4,4,0,64,1,13,0,65,1,12,0,62,1,14,0,60,1,15,0,0,0,0,6,2,15,62,1,2,0,62,1,0,0,62,1,3,0,62,1,4,0,62,1,6,0,62,1,7,0,62,1,8,0,65,1,10,0,67,1,11,0,69,2,12,0,74,2,0,0,74,2,6,0,72,2,3,0,81,2,12,0,77,2,9,0,0,0,0,6,2,16,67,1,3,0,69,1,4,0,67,1,5,0,65,1,6,0,64,1,7,0,67,1,8,0,65,1,9,0,64,1,10,0,60,1,11,0,62,2,12,0,62,1,15,0,74,2,4,0,69,4,0,0,72,2,8,0,77,2,0,0,69,2,12,0,0,0,0,6,2,19,64,1,2,0,65,1,3,0,67,2,4,0,65,1,0,0,64,2,6,0,67,1,8,0,67,1,9,0,65,1,10,0,67,1,11,0,69,2,12,0,69,2,0,0,72,2,4,0,76,1,7,0,72,1,11,0,79,1,8,0,79,1,9,0,69,2,14,0,74,2,12,0,74,2,14,0,0,0,0,6,2,13,72,2,4,0,64,2,4,0,74,2,0,0,74,2,2,0,62,2,2,0,64,2,10,0,57,2,10,0,69,4,6,0,60,4,6,0,53,2,14,0,55,2,12,0,62,1,0,0,62,1,1,0,0,0,0,6,2,14,74,1,0,0,77,1,1,0,79,1,2,0,81,1,3,0,69,2,0,0,86,4,4,0,86,2,10,0,81,2,12,0,77,2,4,0,84,1,9,0,84,1,8,0,81,2,8,0,77,2,12,0,79,2,14,0,0,0,0,6,2,10,65,2,0,0,62,2,2,0,77,2,0,0,74,2,2,0,69,6,4,0,64,6,4,0,67,2,10,0,60,2,14,0,64,1,12,0,64,1,13,0,0,0,0,6,2,8,57,2,0,0,55,2,2,0,48,2,6,0,52,1,4,0,52,1,5,0,45,2,8,0,50,4,10,0,57,2,14,0,0,0,0,0,0,18,45,2,0,0,46,1,2,0,45,2,3,0,46,1,5,0,43,2,6,0,43,2,8,0,41,1,10,0,43,1,11,0,45,1,12,0,43,1,13,0,41,1,14,0,38,1,15,0,46,1,10,0,48,1,11,0,48,1,13,0,46,1,14,0,43,1,15,0,50,1,12,0,0,0,0,0,0,18,36,1,0,0,38,2,1,0,36,1,5,0,38,2,6,0,36,1,10,0,33,1,11,0,31,1,12,0,38,2,3,0,38,2,8,0,41,1,10,0,38,1,11,0,36,1,12,0,33,1,13,0,31,1,14,0,29,1,15,0,29,1,13,0,41,1,0,0,26,1,14,0,0,0,0,0,0,18,31,2,0,0,31,2,2,0,31,2,5,0,36,1,7,0,41,1,8,0,43,1,9,0,31,1,7,0,36,1,8,0,38,1,9,0,46,2,10,0,43,2,10,0,34,1,4,0,45,1,12,0,41,1,12,0,43,2,13,0,38,2,13,0,36,1,15,0,41,1,15,0,0,0,0,0,0,22,43,2,2,0,38,2,2,0,46,1,4,0,43,2,5,0,48,1,8,0,50,1,9,0,46,1,7,0,53,1,10,0,55,1,11,0,53,1,12,0,50,1,13,0,48,1,14,0,46,1,15,0,43,1,14,0,45,1,13,0,48,1,12,0,50,1,11,0,41,1,15,0,38,1,0,0,36,1,1,0,33,1,0,0,41,1,1,0,0,0,0,7,20,10,62,1,0,0,62,1,4,0,62,1,8,0,62,1,12,0,74,1,1,0,47,1,0,0,47,1,4,0,47,1,8,0,47,1,12,0,57,1,10,0,0,0,0,8,20,6,84,1,0,0,84,1,6,0,84,1,10,0,84,1,12,0,84,1,14,0,84,1,3,0,0,5,0,9,0,16,77,1,0,0,80,1,1,0,82,1,2,0,84,1,3,0,89,1,4,0,84,1,5,0,82,1,6,0,77,1,7,0,75,1,8,0,77,1,9,0,82,1,10,0,77,1,11,0,75,1,12,0,72,1,13,0,68,1,14,0,65,1,15,0,0,5,0,9,0,16,72,1,0,0,72,1,2,0,68,1,1,0,68,1,3,0,65,1,4,0,60,1,5,0,65,1,6,0,68,1,7,0,68,1,9,0,70,1,10,0,72,1,11,0,70,1,8,0,75,1,12,0,72,1,13,0,70,1,14,0,68,2,15,0,0,5,0,9,0,13,68,1,2,0,70,1,3,0,72,1,4,0,75,1,5,0,77,1,6,0,84,1,7,0,89,2,8,0,84,1,10,0,89,2,11,0,84,1,13,0,65,1,1,0,87,1,14,0,89,1,15,0,0,5,0,9,0,16,77,1,0,0,80,1,1,0,82,1,2,0,84,1,3,0,77,1,4,0,80,1,5,0,82,1,6,0,84,1,7,0,77,1,8,0,80,1,9,0,82,1,10,0,84,1,11,0,87,1,12,0,89,1,13,0,96,1,14,0,89,1,15,0,0,5,0,9,0,16,87,1,0,0,84,1,1,0,82,1,2,0,80,1,3,0,77,1,4,0,75,1,5,0,72,1,6,0,75,1,7,0,77,1,8,0,75,1,9,0,72,1,10,0,75,1,11,0,77,1,12,0,75,1,13,0,72,1,14,0,75,1,15,0,0,5,0,9,0,16,84,1,0,0,84,1,4,0,89,1,7,0,87,1,8,0,84,1,9,0,82,1,10,0,80,1,11,0,77,1,12,0,75,1,13,0,72,1,14,0,70,1,15,0,87,1,1,0,89,1,2,0,87,1,3,0,82,1,5,0,87,1,6,0,0,5,0,9,0,16,68,1,0,0,65,1,1,0,63,1,2,0,60,1,3,0,63,1,4,0,60,1,5,0,58,1,6,0,56,1,7,0,53,1,8,0,56,1,9,0,58,1,10,0,60,1,11,0,63,1,12,0,60,1,13,0,58,1,14,0,60,1,15,0,0,5,0,9,0,16,63,1,0,0,65,1,1,0,68,1,2,0,65,1,3,0,72,1,6,0,75,1,7,0,77,1,8,0,75,1,9,0,72,1,10,0,75,1,11,0,75,1,13,0,72,1,14,0,75,1,15,0,68,1,4,0,70,1,5,0,77,1,12,0,0,5,0,10,1,8,41,1,0,0,44,1,2,0,41,1,4,0,36,1,6,0,39,1,8,0,41,1,10,0,44,1,12,0,46,1,14,0,0,5,0,10,1,9,48,1,0,0,51,1,2,0,53,1,4,0,51,1,6,0,48,1,7,0,46,1,9,0,46,1,11,0,44,1,13,0,41,1,15,0,0,5,0,10,1,9,39,1,0,0,36,1,2,0,39,1,4,0,41,1,6,0,44,1,8,0,44,1,10,0,41,1,11,0,41,1,13,0,39,1,15,0,0,5,0,10,1,9,41,1,0,0,44,1,2,0,46,1,4,0,48,1,6,0,51,1,8,0,53,1,10,0,51,1,12,0,48,1,13,0,48,1,15,0,0,5,0,10,1,10,46,1,0,0,44,1,2,0,41,1,4,0,48,1,5,0,53,1,6,0,60,1,7,0,58,1,8,0,53,1,12,0,53,1,14,0,56,1,10,0,0,5,0,10,1,8,53,1,0,0,53,1,2,0,51,1,4,0,46,1,6,0,48,1,8,0,48,1,10,0,46,1,12,0,48,1,14,0,0,5,0,10,1,8,48,1,0,0,46,1,2,0,41,1,4,0,41,1,6,0,44,1,8,0,46,1,10,0,48,1,12,0,51,1,14,0,0,5,0,10,1,9,48,1,14,0,44,1,15,0,53,1,0,0,51,1,2,0,48,1,4,0,46,1,6,0,44,1,8,0,51,1,12,0,48,1,10,0,0,0,0,9,0,7,36,8,0,0,36,2,8,0,36,2,10,0,36,1,12,0,36,1,13,0,36,1,14,0,36,1,15,0,0,0,0,9,0,11,36,1,0,0,39,1,1,0,41,1,2,0,43,1,3,0,48,2,4,0,48,2,6,0,43,1,8,0,41,1,9,0,39,1,10,0,41,1,11,0,43,4,12,0,0,0,0,9,0,10,41,1,0,0,39,1,1,0,38,1,2,0,39,1,3,0,41,4,4,0,39,1,8,0,38,1,9,0,36,1,10,0,38,1,11,0,39,4,12,0,0,0,0,9,0,13,38,1,0,0,36,1,1,0,34,1,2,0,31,1,3,0,39,1,7,0,43,1,8,0,48,1,9,0,43,1,10,0,39,1,11,0,34,1,4,0,36,2,5,0,36,1,12,0,36,1,14,0,0,0,0,9,0,10,34,1,0,0,32,1,3,0,32,1,5,0,31,1,8,0,31,1,12,0,36,1,15,0,32,1,1,0,31,1,10,0,36,1,13,0,32,1,7,0,0,0,0,9,0,11,36,1,1,0,39,1,2,0,43,1,3,0,48,1,4,0,51,3,5,0,50,1,8,0,48,1,9,0,51,2,10,0,50,1,12,0,48,1,13,0,55,1,14,0,0,0,0,9,0,12,48,4,14,0,53,1,4,0,53,1,5,0,51,1,8,0,50,1,12,0,55,1,0,0,55,1,1,0,46,1,13,0,51,1,9,0,53,1,2,0,51,1,6,0,50,1,10,0,0,0,0,9,0,10,51,1,2,0,55,1,3,0,60,1,4,0,63,1,5,0,67,1,6,0,67,2,7,0,63,1,9,0,60,4,10,0,58,1,14,0,56,1,15,0,0,0,0,9,0,9,55,1,0,0,53,1,2,0,51,1,4,0,46,1,10,0,46,2,12,0,48,2,14,0,50,1,6,0,50,1,7,0,46,1,8,0,0,0,0,9,0,11,48,1,0,0,43,1,3,0,36,1,4,0,36,1,5,0,36,1,8,0,39,1,9,0,31,2,6,0,48,2,10,0,46,2,12,0,44,2,14,0,43,1,1,0,0,0,0,9,0,4,43,4,0,0,41,4,4,0,39,4,8,0,38,4,12,0,0,0,0,2,20,14,1,1,0,0,1,1,2,0,1,1,4,0,1,1,6,0,1,1,8,0,1,1,10,0,1,1,12,0,1,1,14,0,6,1,4,0,6,1,6,0,6,1,12,0,6,1,14,0,6,1,2,0,6,1,10,0,0,0,0,2,20,0,0,7,5,7,0,-1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,2,-1,-1,-1,-1,-1,-1,-1,32,-1,-1,-1,-1,-1,-1,-1,33,-1,-1,-1,-1,-1,-1,-1,34,-1,-1,-1,-1,-1,-1,-1,35,-1,-1,-1,-1,-1,-1,-1, \ No newline at end of file diff --git a/res/img/fruit.png b/res/img/fruit.png new file mode 100644 index 0000000..7301d6c Binary files /dev/null and b/res/img/fruit.png differ diff --git a/res/img/letters/a.png b/res/img/letters/a.png new file mode 100644 index 0000000..fe743b8 Binary files /dev/null and b/res/img/letters/a.png differ diff --git a/res/img/letters/b.png b/res/img/letters/b.png new file mode 100644 index 0000000..8ebe2bb Binary files /dev/null and b/res/img/letters/b.png differ diff --git a/res/img/letters/c.png b/res/img/letters/c.png new file mode 100644 index 0000000..ef45189 Binary files /dev/null and b/res/img/letters/c.png differ diff --git a/res/img/letters/d.png b/res/img/letters/d.png new file mode 100644 index 0000000..ada338f Binary files /dev/null and b/res/img/letters/d.png differ diff --git a/res/img/letters/e.png b/res/img/letters/e.png new file mode 100644 index 0000000..fc48a06 Binary files /dev/null and b/res/img/letters/e.png differ diff --git a/res/img/letters/f.png b/res/img/letters/f.png new file mode 100644 index 0000000..f2eed9c Binary files /dev/null and b/res/img/letters/f.png differ diff --git a/res/img/letters/g.png b/res/img/letters/g.png new file mode 100644 index 0000000..686e5c3 Binary files /dev/null and b/res/img/letters/g.png differ diff --git a/res/img/letters/h.png b/res/img/letters/h.png new file mode 100644 index 0000000..b7d0bc3 Binary files /dev/null and b/res/img/letters/h.png differ diff --git a/res/img/letters/i.png b/res/img/letters/i.png new file mode 100644 index 0000000..f756fa4 Binary files /dev/null and b/res/img/letters/i.png differ diff --git a/res/img/letters/j.png b/res/img/letters/j.png new file mode 100644 index 0000000..efdd618 Binary files /dev/null and b/res/img/letters/j.png differ diff --git a/res/img/letters/k.png b/res/img/letters/k.png new file mode 100644 index 0000000..15fc05a Binary files /dev/null and b/res/img/letters/k.png differ diff --git a/res/img/letters/l.png b/res/img/letters/l.png new file mode 100644 index 0000000..7045fa1 Binary files /dev/null and b/res/img/letters/l.png differ diff --git a/res/img/letters/m.png b/res/img/letters/m.png new file mode 100644 index 0000000..0f58dd1 Binary files /dev/null and b/res/img/letters/m.png differ diff --git a/res/img/letters/n.png b/res/img/letters/n.png new file mode 100644 index 0000000..3bdb55e Binary files /dev/null and b/res/img/letters/n.png differ diff --git a/res/img/letters/o.png b/res/img/letters/o.png new file mode 100644 index 0000000..e9102e8 Binary files /dev/null and b/res/img/letters/o.png differ diff --git a/res/img/letters/q.png b/res/img/letters/q.png new file mode 100644 index 0000000..6685484 Binary files /dev/null and b/res/img/letters/q.png differ diff --git a/res/img/letters/r.png b/res/img/letters/r.png new file mode 100644 index 0000000..5be6f86 Binary files /dev/null and b/res/img/letters/r.png differ diff --git a/res/img/letters/s.png b/res/img/letters/s.png new file mode 100644 index 0000000..7fd5c65 Binary files /dev/null and b/res/img/letters/s.png differ diff --git a/res/img/letters/t.png b/res/img/letters/t.png new file mode 100644 index 0000000..7a78605 Binary files /dev/null and b/res/img/letters/t.png differ diff --git a/res/img/letters/v.png b/res/img/letters/v.png new file mode 100644 index 0000000..184c6a9 Binary files /dev/null and b/res/img/letters/v.png differ diff --git a/res/img/letters/w.png b/res/img/letters/w.png new file mode 100644 index 0000000..029ef2f Binary files /dev/null and b/res/img/letters/w.png differ diff --git a/res/img/letters/x.png b/res/img/letters/x.png new file mode 100644 index 0000000..d821267 Binary files /dev/null and b/res/img/letters/x.png differ diff --git a/res/img/letters/y.png b/res/img/letters/y.png new file mode 100644 index 0000000..852ccef Binary files /dev/null and b/res/img/letters/y.png differ diff --git a/res/img/letters/z.png b/res/img/letters/z.png new file mode 100644 index 0000000..1b2e097 Binary files /dev/null and b/res/img/letters/z.png differ diff --git a/res/img/toxin.png b/res/img/toxin.png new file mode 100644 index 0000000..d282a28 Binary files /dev/null and b/res/img/toxin.png differ diff --git a/res/levels/all/countdown.fx b/res/levels/all/countdown.fx new file mode 100644 index 0000000..3e33dda --- /dev/null +++ b/res/levels/all/countdown.fx @@ -0,0 +1,19 @@ +3 + +1 false true 1 1 +0 1 1 1 +0 1 0.3 1 +0 1 1 0.25 +0 0 0 0.25 + +1 false true 1 1 +60 1 1 1 +0 0 0 1 +60 1 1 0.25 +0 0 0 0.25 + +1 false true 1 1 +120 1 1 1 +0 0 0 1 +120 1 1 0.25 +0 0 0 0.25 \ No newline at end of file diff --git a/res/levels/all/defeat.fx b/res/levels/all/defeat.fx new file mode 100644 index 0000000..6ccc8ae --- /dev/null +++ b/res/levels/all/defeat.fx @@ -0,0 +1,7 @@ +1 + +3 true true 2 0.5 +0.7 0 0 1 +0.3 0 0 1 +0.7 0 0 1 +0.3 0 0 1 \ No newline at end of file diff --git a/res/levels/all/length.png b/res/levels/all/length.png new file mode 100644 index 0000000..fa7be08 Binary files /dev/null and b/res/levels/all/length.png differ diff --git a/res/levels/all/next/hovered.fx b/res/levels/all/next/hovered.fx new file mode 100644 index 0000000..919f45a --- /dev/null +++ b/res/levels/all/next/hovered.fx @@ -0,0 +1,7 @@ +1 + +3 true true 2 0.5 +0 1 0 1 +0 0.5 0 1 +0 1 0 1 +0 0.5 0 1 \ No newline at end of file diff --git a/res/levels/all/next/next.png b/res/levels/all/next/next.png new file mode 100644 index 0000000..d6a0c83 Binary files /dev/null and b/res/levels/all/next/next.png differ diff --git a/res/levels/all/next/pressed.fx b/res/levels/all/next/pressed.fx new file mode 100644 index 0000000..6f1bc52 --- /dev/null +++ b/res/levels/all/next/pressed.fx @@ -0,0 +1,7 @@ +1 + +3 true true 2 0.5 +0 0.4 0 1 +0 0.2 0 1 +0 0.4 0 1 +0 0.2 0 1 \ No newline at end of file diff --git a/res/levels/all/next/space.png b/res/levels/all/next/space.png new file mode 100644 index 0000000..6e1e8ff Binary files /dev/null and b/res/levels/all/next/space.png differ diff --git a/res/levels/all/next/unpressed.fx b/res/levels/all/next/unpressed.fx new file mode 100644 index 0000000..8aa619a --- /dev/null +++ b/res/levels/all/next/unpressed.fx @@ -0,0 +1,7 @@ +1 + +3 true true 2 0.5 +0.8 0.8 0.8 1 +0.5 1 0.5 1 +0.8 0.8 0.8 1 +0.5 1 0.5 1 \ No newline at end of file diff --git a/res/levels/all/one.png b/res/levels/all/one.png new file mode 100644 index 0000000..782f14f Binary files /dev/null and b/res/levels/all/one.png differ diff --git a/res/levels/all/retry/hovered.fx b/res/levels/all/retry/hovered.fx new file mode 100644 index 0000000..0836a94 --- /dev/null +++ b/res/levels/all/retry/hovered.fx @@ -0,0 +1,7 @@ +1 + +3 true true 2 0.5 +1 0 0 1 +0.5 0 0 1 +1 0 0 1 +0.5 0 0 1 \ No newline at end of file diff --git a/res/levels/all/retry/pressed.fx b/res/levels/all/retry/pressed.fx new file mode 100644 index 0000000..736bcc1 --- /dev/null +++ b/res/levels/all/retry/pressed.fx @@ -0,0 +1,7 @@ +1 + +3 true true 2 0.5 +0.4 0 0 1 +0.2 0 0 1 +0.4 0 0 1 +0.2 0 0 1 \ No newline at end of file diff --git a/res/levels/all/retry/retry.png b/res/levels/all/retry/retry.png new file mode 100644 index 0000000..facf20f Binary files /dev/null and b/res/levels/all/retry/retry.png differ diff --git a/res/levels/all/retry/space.png b/res/levels/all/retry/space.png new file mode 100644 index 0000000..2d4c2e6 Binary files /dev/null and b/res/levels/all/retry/space.png differ diff --git a/res/levels/all/retry/unpressed.fx b/res/levels/all/retry/unpressed.fx new file mode 100644 index 0000000..9a69afc --- /dev/null +++ b/res/levels/all/retry/unpressed.fx @@ -0,0 +1,7 @@ +1 + +3 true true 2 0.5 +0.8 0.8 0.8 1 +1 0.5 0.5 1 +0.8 0.8 0.8 1 +1 0.5 0.5 1 \ No newline at end of file diff --git a/res/levels/all/speed.png b/res/levels/all/speed.png new file mode 100644 index 0000000..a1dbb7d Binary files /dev/null and b/res/levels/all/speed.png differ diff --git a/res/levels/all/three.png b/res/levels/all/three.png new file mode 100644 index 0000000..5155a43 Binary files /dev/null and b/res/levels/all/three.png differ diff --git a/res/levels/all/two.png b/res/levels/all/two.png new file mode 100644 index 0000000..d9646d2 Binary files /dev/null and b/res/levels/all/two.png differ diff --git a/res/levels/all/victory.fx b/res/levels/all/victory.fx new file mode 100644 index 0000000..45ea946 --- /dev/null +++ b/res/levels/all/victory.fx @@ -0,0 +1,13 @@ +2 + +0.75 false false 0 1 +60 1 1 1 +60 1 1 1 +72 1 0.5 1 +36 1 0.5 1 + +0.25 false false 0 1 +72 1 0.5 1 +36 1 0.5 1 +60 1 1 1 +60 1 1 1 \ No newline at end of file diff --git a/res/levels/level1/data.prop b/res/levels/level1/data.prop new file mode 100644 index 0000000..9f2483a --- /dev/null +++ b/res/levels/level1/data.prop @@ -0,0 +1,2 @@ +8 +5 \ No newline at end of file diff --git a/res/levels/level1/effect.fx b/res/levels/level1/effect.fx new file mode 100644 index 0000000..e79a561 --- /dev/null +++ b/res/levels/level1/effect.fx @@ -0,0 +1,7 @@ +1 + +2 true true 0.5 2 +0 1 1 1 +1 0 0 1 +0 1 1 1 +1 0 0 1 \ No newline at end of file diff --git a/res/levels/level1/level.png b/res/levels/level1/level.png new file mode 100644 index 0000000..0176fe7 Binary files /dev/null and b/res/levels/level1/level.png differ diff --git a/res/levels/level1/music.wav b/res/levels/level1/music.wav new file mode 100644 index 0000000..d75d054 Binary files /dev/null and b/res/levels/level1/music.wav differ diff --git a/res/levels/level2/data.prop b/res/levels/level2/data.prop new file mode 100644 index 0000000..47ca0e6 --- /dev/null +++ b/res/levels/level2/data.prop @@ -0,0 +1,2 @@ +8 +20 \ No newline at end of file diff --git a/res/levels/level2/effect.fx b/res/levels/level2/effect.fx new file mode 100644 index 0000000..9c4cdc1 --- /dev/null +++ b/res/levels/level2/effect.fx @@ -0,0 +1,7 @@ +1 + +2 true true 0.5 2 +0.6666 0 1 1 +1 0.5 0 1 +0.6666 0 1 1 +1 0.5 0 1 \ No newline at end of file diff --git a/res/levels/level2/level.png b/res/levels/level2/level.png new file mode 100644 index 0000000..1e37b12 Binary files /dev/null and b/res/levels/level2/level.png differ diff --git a/res/levels/level2/music.wav b/res/levels/level2/music.wav new file mode 100644 index 0000000..b958f3b Binary files /dev/null and b/res/levels/level2/music.wav differ diff --git a/res/levels/level3/data.prop b/res/levels/level3/data.prop new file mode 100644 index 0000000..539863d --- /dev/null +++ b/res/levels/level3/data.prop @@ -0,0 +1,2 @@ +8 +10 \ No newline at end of file diff --git a/res/levels/level3/effect.fx b/res/levels/level3/effect.fx new file mode 100644 index 0000000..144dc24 --- /dev/null +++ b/res/levels/level3/effect.fx @@ -0,0 +1,7 @@ +1 + +10 false false 0 1 +0 0.75 0.5 1 +0 0.75 0.5 1 +360 0.75 0.5 1 +360 0.75 0.5 1 \ No newline at end of file diff --git a/res/levels/level3/level.png b/res/levels/level3/level.png new file mode 100644 index 0000000..d042155 Binary files /dev/null and b/res/levels/level3/level.png differ diff --git a/res/levels/level3/music.wav b/res/levels/level3/music.wav new file mode 100644 index 0000000..678ffac Binary files /dev/null and b/res/levels/level3/music.wav differ diff --git a/res/levels/level4/data.prop b/res/levels/level4/data.prop new file mode 100644 index 0000000..81882f0 --- /dev/null +++ b/res/levels/level4/data.prop @@ -0,0 +1,2 @@ +5 +10 \ No newline at end of file diff --git a/res/levels/level4/effect.fx b/res/levels/level4/effect.fx new file mode 100644 index 0000000..05e8621 --- /dev/null +++ b/res/levels/level4/effect.fx @@ -0,0 +1,7 @@ +1 + +4 false false 1 1 +0 1 1 1 +360 1 1 1 +0 1 1 1 +360 1 1 1 \ No newline at end of file diff --git a/res/levels/level4/level.png b/res/levels/level4/level.png new file mode 100644 index 0000000..4bd959c Binary files /dev/null and b/res/levels/level4/level.png differ diff --git a/res/levels/level4/music.wav b/res/levels/level4/music.wav new file mode 100644 index 0000000..bcdb921 Binary files /dev/null and b/res/levels/level4/music.wav differ diff --git a/res/menu/data.prop b/res/menu/data.prop new file mode 100644 index 0000000..ec385ae --- /dev/null +++ b/res/menu/data.prop @@ -0,0 +1,2 @@ +6 +5 \ No newline at end of file diff --git a/res/menu/effect.fx b/res/menu/effect.fx new file mode 100644 index 0000000..d9072b6 --- /dev/null +++ b/res/menu/effect.fx @@ -0,0 +1,7 @@ +1 + +4 false false 1 1 +0 0.5 0.1 1 +360 0.5 0.1 1 +0 0.5 0.1 1 +360 0.5 0.1 1 \ No newline at end of file diff --git a/res/menu/hovered.fx b/res/menu/hovered.fx new file mode 100644 index 0000000..81e9053 --- /dev/null +++ b/res/menu/hovered.fx @@ -0,0 +1,7 @@ +1 + +2 false true -1 1 +40 1 1 1 +0 1 1 1 +40 1 1 1 +0 1 1 1 \ No newline at end of file diff --git a/res/menu/level.png b/res/menu/level.png new file mode 100644 index 0000000..d17f44a Binary files /dev/null and b/res/menu/level.png differ diff --git a/res/menu/logo.fx b/res/menu/logo.fx new file mode 100644 index 0000000..def2596 --- /dev/null +++ b/res/menu/logo.fx @@ -0,0 +1,7 @@ +1 + +3 false true 1 1 +130 1 0.75 1 +170 1 0.15 1 +130 1 0.75 1 +170 1 0.15 1 \ No newline at end of file diff --git a/res/menu/logo.png b/res/menu/logo.png new file mode 100644 index 0000000..bf38bff Binary files /dev/null and b/res/menu/logo.png differ diff --git a/res/menu/music.wav b/res/menu/music.wav new file mode 100644 index 0000000..9dfdfee Binary files /dev/null and b/res/menu/music.wav differ diff --git a/res/menu/play.png b/res/menu/play.png new file mode 100644 index 0000000..9da6be9 Binary files /dev/null and b/res/menu/play.png differ diff --git a/res/menu/pressed.fx b/res/menu/pressed.fx new file mode 100644 index 0000000..a1fe778 --- /dev/null +++ b/res/menu/pressed.fx @@ -0,0 +1,7 @@ +1 + +2 false true -1 1 +40 1 0.25 1 +0 1 0.25 1 +40 1 0.25 1 +0 1 0.25 1 \ No newline at end of file diff --git a/res/shaders/s2a/frag.gls b/res/shaders/s2a/frag.gls new file mode 100644 index 0000000..1bee287 --- /dev/null +++ b/res/shaders/s2a/frag.gls @@ -0,0 +1,13 @@ +#version 330 core + +uniform sampler2D sampler; + +in vec2 texCoords; + +out vec4 color; + +void main() { + color = texture(sampler, texCoords); + if(color.a == 0) + discard; +} \ No newline at end of file diff --git a/res/shaders/s2a/vert.gls b/res/shaders/s2a/vert.gls new file mode 100644 index 0000000..065439e --- /dev/null +++ b/res/shaders/s2a/vert.gls @@ -0,0 +1,15 @@ +#version 330 core + +uniform mat4 mvp; + +uniform vec2 animProps; // Loc 0 - Frame Width, Loc 1 - Offset + +layout (location = 0) in vec3 vertices; +layout (location = 1) in vec2 iTexCoords; + +out vec2 texCoords; + +void main() { + texCoords = vec2(((iTexCoords.x * animProps.x) + animProps.y), iTexCoords.y); + gl_Position = mvp * vec4(vertices, 1.0); +} diff --git a/res/shaders/s2c/frag.gls b/res/shaders/s2c/frag.gls new file mode 100644 index 0000000..1481224 --- /dev/null +++ b/res/shaders/s2c/frag.gls @@ -0,0 +1,9 @@ +#version 330 core + +uniform vec4 iColor = vec4(0, 0.6, 0.9, 1); + +out vec4 color; + +void main() { + color = iColor; +} \ No newline at end of file diff --git a/res/shaders/s2c/vert.gls b/res/shaders/s2c/vert.gls new file mode 100644 index 0000000..f404630 --- /dev/null +++ b/res/shaders/s2c/vert.gls @@ -0,0 +1,9 @@ +#version 330 core + +uniform mat4 mvp; + +layout (location = 0) in vec3 vertices; + +void main() { + gl_Position = mvp * vec4(vertices, 1); +} \ No newline at end of file diff --git a/res/shaders/s2le/frag.gls b/res/shaders/s2le/frag.gls new file mode 100644 index 0000000..3cb38e1 --- /dev/null +++ b/res/shaders/s2le/frag.gls @@ -0,0 +1,46 @@ +#version 330 core + +uniform sampler2D sampler; + +uniform vec4 color1 = vec4(0, 1, 1, 1); +uniform vec4 color2 = vec4(0, 0, 1, 1); +uniform float time = 0, freq = 1; +uniform bool rgb = true, loop = false, textured = false; + +in vec2 iTexCoords; +in float percent; + +out vec4 color; + +vec4 hsvToRgb(vec4 hsva); + +void main() { + vec4 tcolor; + if(textured) + tcolor = texture(sampler, iTexCoords); + if(!textured || tcolor.xyz == vec3(1, 1, 1)) { + float finalPercent = mod((percent + time) * freq, 1); + if(loop) { + if(finalPercent > 0.5) + finalPercent = 1 - finalPercent; + finalPercent *= 2; + } + vec4 interpolated = color1 + (color2 - color1) * finalPercent; + if(rgb) + color = interpolated; + else + color = hsvToRgb(interpolated); + if(textured) + color.w = texture(sampler, iTexCoords).w; + } + else if(tcolor.w != 0) + color = tcolor; + else + discard; +} + +vec4 hsvToRgb(vec4 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return vec4(c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y), c.w); +} \ No newline at end of file diff --git a/res/shaders/s2le/vert.gls b/res/shaders/s2le/vert.gls new file mode 100644 index 0000000..65356eb --- /dev/null +++ b/res/shaders/s2le/vert.gls @@ -0,0 +1,16 @@ +#version 330 core + +uniform mat4 mvp; + +layout (location = 0) in vec3 vertices; +layout (location = 1) in vec2 texCoords; + +out vec2 iTexCoords; +out float percent; + +void main() { + iTexCoords = texCoords; + vec4 position = mvp * vec4(vertices, 1); + percent = (position.x + 1) / 4 - (position.y - 1) / 4; + gl_Position = position; +} \ No newline at end of file diff --git a/res/shaders/s2t/frag.gls b/res/shaders/s2t/frag.gls new file mode 100644 index 0000000..cbb90a1 --- /dev/null +++ b/res/shaders/s2t/frag.gls @@ -0,0 +1,11 @@ +#version 330 core + +uniform sampler2D sampler; + +in vec2 texCoords; + +out vec4 color; + +void main() { + color = texture(sampler, texCoords); +} \ No newline at end of file diff --git a/res/shaders/s2t/vert.gls b/res/shaders/s2t/vert.gls new file mode 100644 index 0000000..6c3699d --- /dev/null +++ b/res/shaders/s2t/vert.gls @@ -0,0 +1,13 @@ +#version 330 core + +uniform mat4 mvp; + +layout (location = 0) in vec3 vertices; +layout (location = 1) in vec2 itexCoords; + +out vec2 texCoords; + +void main() { + texCoords = itexCoords; + gl_Position = mvp * vec4(vertices, 1); +} \ No newline at end of file diff --git a/res/shaders/s2x/frag.gls b/res/shaders/s2x/frag.gls new file mode 100644 index 0000000..ab4800c --- /dev/null +++ b/res/shaders/s2x/frag.gls @@ -0,0 +1,15 @@ +#version 330 core + +uniform vec4 iColor; + +uniform sampler2D sampler; + +in vec2 texCoords; + +out vec4 color; + +void main() { + color = iColor * texture(sampler, texCoords); + if(color.a == 0) + discard; +} \ No newline at end of file diff --git a/res/shaders/s2x/vert.gls b/res/shaders/s2x/vert.gls new file mode 100644 index 0000000..4bdcfe3 --- /dev/null +++ b/res/shaders/s2x/vert.gls @@ -0,0 +1,15 @@ +#version 330 core + +uniform mat4 mvp; + +uniform vec2 character; + +layout (location = 0) in vec3 vertices; +layout (location = 1) in vec2 iTexCoords; + +out vec2 texCoords; + +void main() { + texCoords = iTexCoords + character; + gl_Position = mvp * vec4(vertices, 1.0); +} \ No newline at end of file diff --git a/src/com/gnarly/engine/audio/ALManagement.java b/src/com/gnarly/engine/audio/ALManagement.java new file mode 100644 index 0000000..00c854b --- /dev/null +++ b/src/com/gnarly/engine/audio/ALManagement.java @@ -0,0 +1,39 @@ +package com.gnarly.engine.audio; + +import static org.lwjgl.openal.ALC10.alcCreateContext; +import static org.lwjgl.openal.ALC10.alcMakeContextCurrent; +import static org.lwjgl.openal.ALC10.alcOpenDevice; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +import org.lwjgl.openal.AL; +import org.lwjgl.openal.ALC; +import org.lwjgl.openal.ALC10; +import org.lwjgl.openal.ALCCapabilities; + +public class ALManagement { + + private long device, context; + private ALCCapabilities deviceCaps; + + public ALManagement() { + device = alcOpenDevice((ByteBuffer) null); + if (device == 0) + throw new IllegalStateException("Failed to open the default device."); + + deviceCaps = ALC.createCapabilities(device); + + context = alcCreateContext(device, (IntBuffer) null); + if (context == 0) + throw new IllegalStateException("Failed to create an OpenAL context."); + + alcMakeContextCurrent(context); + AL.createCapabilities(deviceCaps); + } + + public void destroy() { + ALC10.alcDestroyContext(context); + ALC10.alcCloseDevice(device); + } +} diff --git a/src/com/gnarly/engine/audio/Sound.java b/src/com/gnarly/engine/audio/Sound.java new file mode 100644 index 0000000..2e88ca3 --- /dev/null +++ b/src/com/gnarly/engine/audio/Sound.java @@ -0,0 +1,38 @@ +package com.gnarly.engine.audio; + +import org.lwjgl.openal.AL10; + +public class Sound { + + private int buffer; + private int sourceId; + + public Sound(String path) { + sourceId = AL10.alGenSources(); + buffer = AL10.alGenBuffers(); + WaveData waveData = WaveData.create(path); + AL10.alBufferData(buffer, waveData.format, waveData.data, waveData.samplerate); + AL10.alSourcei(sourceId, AL10.AL_BUFFER, buffer); + AL10.alSourcef(sourceId, AL10.AL_GAIN, 1); + AL10.alSourcef(sourceId, AL10.AL_PITCH, 1); + } + + public void play(boolean loop) { + AL10.alSourcei(sourceId, AL10.AL_LOOPING, loop ? 1 : 0); + AL10.alSource3f(sourceId, AL10.AL_POSITION, 0, 0, 0); + AL10.alSourcePlay(sourceId); + } + + public void stop() { + AL10.alSourceStop(sourceId); + } + + public void setVolume(float volume) { + AL10.alSourcef(sourceId, AL10.AL_GAIN, volume); + } + + public void destroy() { + AL10.alDeleteBuffers(buffer); + AL10.alDeleteSources(sourceId); + } +} diff --git a/src/com/gnarly/engine/audio/WaveData.java b/src/com/gnarly/engine/audio/WaveData.java new file mode 100644 index 0000000..3205142 --- /dev/null +++ b/src/com/gnarly/engine/audio/WaveData.java @@ -0,0 +1,88 @@ +package com.gnarly.engine.audio; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.UnsupportedAudioFileException; + +import org.lwjgl.BufferUtils; +import org.lwjgl.openal.AL10; + +public class WaveData { + + final int format; + final int samplerate; + final int totalBytes; + final int bytesPerFrame; + final ByteBuffer data; + + private final AudioInputStream audioStream; + private final byte[] dataArray; + + private WaveData(AudioInputStream stream) { + this.audioStream = stream; + AudioFormat audioFormat = stream.getFormat(); + format = getOpenAlFormat(audioFormat.getChannels(), audioFormat.getSampleSizeInBits()); + this.samplerate = (int) audioFormat.getSampleRate(); + this.bytesPerFrame = audioFormat.getFrameSize(); + this.totalBytes = (int) (stream.getFrameLength() * bytesPerFrame); + this.data = BufferUtils.createByteBuffer(totalBytes); + this.dataArray = new byte[totalBytes]; + loadData(); + } + + protected void dispose() { + try { + audioStream.close(); + data.clear(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private ByteBuffer loadData() { + try { + int bytesRead = audioStream.read(dataArray, 0, totalBytes); + data.clear(); + data.put(dataArray, 0, bytesRead); + data.flip(); + } catch (IOException e) { + e.printStackTrace(); + System.err.println("Couldn't read bytes from audio stream!"); + } + return data; + } + + public static WaveData create(String file) { + WaveData wavStream = null; + try { + InputStream stream = new FileInputStream(new File(file)); + InputStream bufferedInput = new BufferedInputStream(stream); + AudioInputStream audioStream = null; + audioStream = AudioSystem.getAudioInputStream(bufferedInput); + wavStream = new WaveData(audioStream); + } catch (UnsupportedAudioFileException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return wavStream; + } + + + private static int getOpenAlFormat(int channels, int bitsPerSample) { + if (channels == 1) { + return bitsPerSample == 8 ? AL10.AL_FORMAT_MONO8 : AL10.AL_FORMAT_MONO16; + } else { + return bitsPerSample == 8 ? AL10.AL_FORMAT_STEREO8 : AL10.AL_FORMAT_STEREO16; + } + } + +} diff --git a/src/com/gnarly/engine/display/Camera.java b/src/com/gnarly/engine/display/Camera.java new file mode 100644 index 0000000..36d6e6c --- /dev/null +++ b/src/com/gnarly/engine/display/Camera.java @@ -0,0 +1,101 @@ +package com.gnarly.engine.display; + +import org.joml.Matrix4f; +import org.joml.Vector3f; + +public class Camera { + + private Matrix4f projection, projView; + + private float width, height; + private Vector3f position; + private float rotation; + + public Camera(float width, float height) { + setDims(width, height); + position = new Vector3f(); + rotation = 0; + projView = new Matrix4f(); + } + + public void setDims(float width, float height) { + this.width = width; + this.height = height; + projection = new Matrix4f().setOrtho(0, width, height, 0, 0, 1); + } + + public void update() { + projection.translate(position.negate(new Vector3f()), projView); + projView.rotateZ(-rotation); + } + + public Matrix4f getProjection() { + return new Matrix4f(projection); + } + + public Matrix4f getMatrix() { + return new Matrix4f(projView); + } + + public float getX() { + return position.x; + } + + public float getY() { + return position.y; + } + + public Vector3f getPosition() { + return new Vector3f(position); + } + + public float getWidth() { + return width; + } + + public float getHeight() { + return height; + } + + public void setX(float x) { + position.x = x; + } + + public void setY(float y) { + position.y = y; + } + + public void setPosition(float x, float y) { + position.set(x, y, position.z); + } + + public void setPosition(Vector3f position) { + this.position.x = position.x; + this.position.y = position.y; + } + + public void setCenter(float x, float y) { + position.set(x - width / 2, y - height / 2, position.z); + } + + public void setCenter(Vector3f position) { + this.position.x = position.x - width / 2; + this.position.y = position.y - height / 2; + } + + public void translate(float x, float y, float z) { + position.add(x, y, z); + } + + public void translate(Vector3f transform) { + position.add(transform); + } + + public void setRotation(float angle) { + rotation = angle; + } + + public void rotate(float angle) { + rotation += angle; + } +} diff --git a/src/com/gnarly/engine/display/Window.java b/src/com/gnarly/engine/display/Window.java new file mode 100644 index 0000000..7dd01ff --- /dev/null +++ b/src/com/gnarly/engine/display/Window.java @@ -0,0 +1,211 @@ +package com.gnarly.engine.display; + +import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MAJOR; +import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MINOR; +import static org.lwjgl.glfw.GLFW.GLFW_DECORATED; +import static org.lwjgl.glfw.GLFW.GLFW_FALSE; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_LAST; +import static org.lwjgl.glfw.GLFW.GLFW_MAXIMIZED; +import static org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_LAST; +import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_CORE_PROFILE; +import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_FORWARD_COMPAT; +import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_PROFILE; +import static org.lwjgl.glfw.GLFW.GLFW_RESIZABLE; +import static org.lwjgl.glfw.GLFW.GLFW_SAMPLES; +import static org.lwjgl.glfw.GLFW.GLFW_TRUE; +import static org.lwjgl.glfw.GLFW.glfwCreateWindow; +import static org.lwjgl.glfw.GLFW.glfwGetCursorPos; +import static org.lwjgl.glfw.GLFW.glfwGetPrimaryMonitor; +import static org.lwjgl.glfw.GLFW.glfwGetVideoMode; +import static org.lwjgl.glfw.GLFW.glfwGetWindowSize; +import static org.lwjgl.glfw.GLFW.glfwInit; +import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent; +import static org.lwjgl.glfw.GLFW.glfwPollEvents; +import static org.lwjgl.glfw.GLFW.glfwSetErrorCallback; +import static org.lwjgl.glfw.GLFW.glfwSetKeyCallback; +import static org.lwjgl.glfw.GLFW.glfwSetMouseButtonCallback; +import static org.lwjgl.glfw.GLFW.glfwSetWindowShouldClose; +import static org.lwjgl.glfw.GLFW.glfwSetWindowSizeCallback; +import static org.lwjgl.glfw.GLFW.glfwSwapBuffers; +import static org.lwjgl.glfw.GLFW.glfwSwapInterval; +import static org.lwjgl.glfw.GLFW.glfwTerminate; +import static org.lwjgl.glfw.GLFW.glfwWindowHint; +import static org.lwjgl.glfw.GLFW.glfwWindowShouldClose; +import static org.lwjgl.opengl.GL.createCapabilities; +import static org.lwjgl.opengl.GL11.GL_BLEND; +import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; +import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; +import static org.lwjgl.opengl.GL11.GL_DEPTH_TEST; +import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA; +import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; +import static org.lwjgl.opengl.GL11.GL_TRUE; +import static org.lwjgl.opengl.GL11.glBlendFunc; +import static org.lwjgl.opengl.GL11.glClear; +import static org.lwjgl.opengl.GL11.glClearColor; +import static org.lwjgl.opengl.GL11.glEnable; +import static org.lwjgl.opengl.GL11.glViewport; +import static org.lwjgl.opengl.GL13.GL_MULTISAMPLE; + +import org.joml.Vector3f; +import org.lwjgl.glfw.GLFWErrorCallback; +import org.lwjgl.glfw.GLFWVidMode; + +public class Window { + + public static int + SCREEN_WIDTH, + SCREEN_HEIGHT; + + public static float SCALE; + + private long window; + private int width, height; + private boolean resized; + + private int[] mouseButtons = new int[GLFW_MOUSE_BUTTON_LAST + 1]; + private int[] keys = new int[GLFW_KEY_LAST + 1]; + + public Window(String title, boolean vSync) { + init(0, 0, title, vSync, false, false, false); + } + + public Window(String title, boolean vSync, boolean resizable, boolean decorated) { + init(800, 500, title, vSync, resizable, decorated, true); + } + + public Window(int width, int height, String title, boolean vSync, boolean resizable, boolean decorated) { + init(width, height, title, vSync, resizable, decorated, false); + } + + public void init(int lwidth, int lheight, String title, boolean vSync, boolean resizable, boolean decorated, boolean maximized) { + glfwSetErrorCallback(GLFWErrorCallback.createPrint(System.err)); + + for (int i = 0; i < mouseButtons.length; i++) + mouseButtons[i] = 0; + + if(!glfwInit()) { + System.err.println("GLFW failed to initialize!"); + System.exit(-1); + } + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + + glfwWindowHint(GLFW_SAMPLES, 8); + glfwWindowHint(GLFW_RESIZABLE, resizable ? GLFW_TRUE : GLFW_FALSE); + glfwWindowHint(GLFW_DECORATED, decorated ? GLFW_TRUE : GLFW_FALSE); + glfwWindowHint(GLFW_MAXIMIZED, maximized ? GLFW_TRUE : GLFW_FALSE); + + GLFWVidMode vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); + SCREEN_WIDTH = vidMode.width(); + SCREEN_HEIGHT = vidMode.height(); + SCALE = SCREEN_HEIGHT / 1080f; + if(lwidth == 0 || lheight == 0) { + width = vidMode.width(); + height = vidMode.height(); + window = glfwCreateWindow(width, height, title, glfwGetPrimaryMonitor(), 0); + } + else { + this.width = lwidth; + this.height = lheight; + window = glfwCreateWindow(width, height, title, 0, 0); + } + + glfwMakeContextCurrent(window); + createCapabilities(); + + glfwSwapInterval(vSync ? 1 : 0); + + glfwSetWindowSizeCallback(window, (long window, int w, int h) -> { + width = w; + height = h; + resized = true; + glViewport(0, 0, width, height); + }); + + glfwSetMouseButtonCallback(window, (long window, int button, int action, int mods) -> { + mouseButtons[button] = action; + }); + + glfwSetKeyCallback(window, (long window, int key, int scancode, int action, int mods) -> { + keys[key] = action; + }); + + glClearColor(0, 0, 0, 1); + + glEnable(GL_TEXTURE_2D); + + glEnable(GL_DEPTH_TEST); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_MULTISAMPLE); + + int[] awidth = new int[1], aheight = new int[1]; + glfwGetWindowSize(window, awidth, aheight); + width = awidth[0]; + height = aheight[0]; + } + + public void update() { + for (int i = 0; i < mouseButtons.length; i++) + if (mouseButtons[i] == 1) + ++mouseButtons[i]; + for (int i = 0; i < keys.length; i++) + if (keys[i] == 1) + ++keys[i]; + resized = false; + glfwPollEvents(); + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public void clear() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + + public void swap() { + glfwSwapBuffers(window); + } + + public void close() { + glfwSetWindowShouldClose(window, true); + } + + public static void terminate() { + glfwTerminate(); + } + + public boolean shouldClose() { + return glfwWindowShouldClose(window); + } + + public int keyPressed(int keyCode) { + return keys[keyCode]; + } + + public Vector3f getMouseCoords(Camera camera) { + double[] x = new double[1], y = new double[1]; + glfwGetCursorPos(window, x, y); + Vector3f ret = new Vector3f((float) x[0], (float) y[0], 0); + return ret.mul(camera.getWidth() / this.width, camera.getHeight() / this.height, 1); + } + + public int mousePressed(int button) { + return mouseButtons[button]; + } + + public boolean wasResized() { + return resized; + } +} diff --git a/src/com/gnarly/engine/model/Circle.java b/src/com/gnarly/engine/model/Circle.java new file mode 100644 index 0000000..87f249b --- /dev/null +++ b/src/com/gnarly/engine/model/Circle.java @@ -0,0 +1,121 @@ +package com.gnarly.engine.model; + +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.shaders.Shader; +import com.gnarly.engine.shaders.Shader2c; + +public class Circle { + + private static Vao vao; + + private Camera camera; + private Shader2c shader; + private Vector3f position; + private float radius; + private float r, g, b, a; + + public Circle(Camera camera, float x, float y, float z, float radius) { + this.camera = camera; + position = new Vector3f(x, y, z); + this.radius = radius; + shader = Shader.SHADER2C; + r = 1; + g = 0; + b = 0; + a = 1; + if(vao == null) + initVao(); + } + + private void initVao() { + final int NUM_POINTS = 30; + float[] cVertices = new float[NUM_POINTS * 3]; + int[] cIndices = new int[(NUM_POINTS - 2) * 3]; + for (int i = 0; i < cVertices.length; i += 3) { + double angle = Math.PI * 2 * i / (NUM_POINTS * 3); + cVertices[i ] = (float) Math.cos(angle); + cVertices[i + 1] = (float) Math.sin(angle); + cVertices[i + 2] = 0; + } + for (int i = 0; i < cIndices.length; i += 3) { + cIndices[i ] = 0; + cIndices[i + 1] = i / 3 + 1; + cIndices[i + 2] = i / 3 + 2; + } + vao = new Vao(cVertices, cIndices); + } + + public void render() { + shader.enable(); + shader.setMVP(camera.getMatrix().translate(position).scale(radius)); + shader.setColor(r, g, b, a); + vao.render(); + } + + public Vector3f getPosition() { + return position; + } + + public void setX(float x) { + position.x = x; + } + + public void setY(float y) { + position.y = y; + } + + public void setZ(float z) { + position.z = z; + } + + public void setPosition(float x, float y) { + position.x = x; + position.y = y; + } + + public void setPosition(float x, float y, float z) { + position.x = x; + position.y = y; + position.z = z; + } + + public void setPosition(Vector3f position) { + this.position.set(position); + } + + public void translate(float x, float y) { + position.x += x; + position.y += y; + } + + public void translate(float x, float y, float z) { + position.x += x; + position.y += y; + position.z += z; + } + + public void translate(Vector3f position) { + this.position.add(position); + } + + public void setRadius(float radius) { + this.radius = radius; + } + + public void setDiameter(float diameter) { + this.radius = diameter / 2; + } + + public void setColor(float r, float g, float b, float a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + public boolean contains(Vector3f vector) { + return (position.sub(vector, new Vector3f()).lengthSquared() < radius * radius); + } +} diff --git a/src/com/gnarly/engine/model/ColRect.java b/src/com/gnarly/engine/model/ColRect.java new file mode 100644 index 0000000..a5d5187 --- /dev/null +++ b/src/com/gnarly/engine/model/ColRect.java @@ -0,0 +1,37 @@ +package com.gnarly.engine.model; + +import org.joml.Matrix4f; +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.shaders.Shader; +import com.gnarly.engine.shaders.Shader2c; + +public class ColRect extends Rect { + + private Shader2c shader; + + private float r, g, b, a; + + public ColRect(Camera camera, float x, float y, float z, float width, float height, float r, float g, float b, float a, boolean gui) { + super(camera, x, y, z, width, height, 0, gui); + shader = Shader.SHADER2C; + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + public void render() { + shader.enable(); + shader.setColor(r, g, b, a); + Matrix4f cmat = gui ? camera.getProjection() : camera.getMatrix(); + shader.setMVP(cmat.translate(position.add(width * scale / 2, height * scale / 2, 0, new Vector3f())).rotateZ(rotation * 3.1415927f / 180).scale(width * scale, height * scale, 1).translate(-0.5f, -0.5f, 0)); + vao.render(); + shader.disable(); + } + + public void setOpacity(float opacity) { + a = opacity; + } +} diff --git a/src/com/gnarly/engine/model/EffectRect.java b/src/com/gnarly/engine/model/EffectRect.java new file mode 100644 index 0000000..b2692f7 --- /dev/null +++ b/src/com/gnarly/engine/model/EffectRect.java @@ -0,0 +1,54 @@ +package com.gnarly.engine.model; + +import org.joml.Matrix4f; +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.shaders.LevelEffect; +import com.gnarly.engine.shaders.Shader; +import com.gnarly.engine.shaders.Shader2le; +import com.gnarly.engine.texture.Texture; +import com.gnarly.game.Main; + +public class EffectRect extends Rect { + + private Shader2le shader = Shader.SHADER2LE; + + private Texture texture; + + private LevelEffect effect; + + public EffectRect(Camera camera, String path, float x, float y, float z, float width, float height, boolean gui) { + super(camera, x, y, z, width, height, 0, gui); + effect = new LevelEffect(path); + texture = null; + } + + public EffectRect(Camera camera, String effect, String texture, float x, float y, float z, float width, float height, boolean gui) { + super(camera, x, y, z, width, height, 0, gui); + this.effect = new LevelEffect(effect); + this.texture = new Texture(texture); + this.gui = gui; + } + + public void render() { + if(texture != null) + texture.bind(); + shader.enable(); + shader.setEffect(effect.getPayload(Main.ttime), texture != null); + Matrix4f cmat = gui ? camera.getProjection() : camera.getMatrix(); + shader.setMVP(cmat.translate(position.add(width * scale / 2, height * scale / 2, 0, new Vector3f())).rotateZ(rotation * 3.1415927f / 180).scale(width * scale, height * scale, 1).translate(-0.5f, -0.5f, 0)); + vao.render(); + shader.disable(); + if(texture != null) + texture.unbind(); + } + + public void setEffect(String path) { + effect = new LevelEffect(path); + } + + public void setTexture(String path) { + texture = new Texture(path); + } +} diff --git a/src/com/gnarly/engine/model/Line.java b/src/com/gnarly/engine/model/Line.java new file mode 100644 index 0000000..a78b6b1 --- /dev/null +++ b/src/com/gnarly/engine/model/Line.java @@ -0,0 +1,118 @@ +package com.gnarly.engine.model; + +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.shaders.Shader; +import com.gnarly.engine.shaders.Shader2c; + +public class Line { + + private static Vao cap, rect; + + private Camera camera; + private Shader2c shader; + + private Vector3f position; + private float angle, length, thickness; + private float r, g, b, a; + + public Line(Camera camera, float x1, float y1, float x2, float y2, float depth, float thickness) { + this.camera = camera; + shader = Shader.SHADER2C; + if(cap == null) + initVaos(); + this.thickness = thickness; + position = new Vector3f(x1, y1, depth); + setPoints(x1, y1, x2, y2); + r = 1; + g = 1; + b = 1; + a = 1; + } + + private void initVaos() { + float[] rVertices = { + 0, 0.5f, 0, + 0, -0.5f, 0, + 1, -0.5f, 0, + 1, 0.5f, 0 + }; + int rIndices[] = { + 0, 1, 3, + 1, 2, 3 + }; + rect = new Vao(rVertices, rIndices); + final int NUM_POINTS = 10; + float[] cVertices = new float[NUM_POINTS * 3]; + int[] cIndices = new int[(NUM_POINTS - 2) * 3]; + for (int i = 0; i < cVertices.length; i += 3) { + double angle = Math.PI * i / (NUM_POINTS * 3 - 3) + Math.PI / 2; + cVertices[i ] = (float) Math.cos(angle) / 2; + cVertices[i + 1] = (float) Math.sin(angle) / 2; + cVertices[i + 2] = 0; + } + for (int i = 0; i < cIndices.length; i += 3) { + cIndices[i ] = 0; + cIndices[i + 1] = i / 3 + 1; + cIndices[i + 2] = i / 3 + 2; + } + cap = new Vao(cVertices, cIndices); + } + + public void render() { + shader.enable(); + shader.setColor(r, g, b, a); + shader.setMVP(camera.getMatrix().translate(position).rotateZ(angle).scale(thickness)); + cap.render(); + shader.setMVP(camera.getMatrix().translate(position).rotateZ(angle).scale(length, thickness, 1)); + rect.render(); + shader.setMVP(camera.getMatrix().translate(position.add((float) (Math.cos(angle) * length), (float) (-Math.sin(Math.PI + angle) * length), 0, new Vector3f())).rotateZ((float) Math.PI).rotateZ(angle).scale(thickness)); + cap.render(); + shader.disable(); + } + + public void setAngle(float x, float y, float angle, float length) { + position.x = x; + position.y = y; + this.angle = angle; + this.length = length; + } + + public void setPoints(float x1, float y1, float x2, float y2) { + float xl = x2 - x1; + float yl = y2 - y1; + length = (float) Math.sqrt(xl * xl + yl * yl); + if(x1 != x2) { + angle = (float) Math.atan(yl / xl); + if(xl < 0) + angle += Math.PI; + setAngle(x1, y1, angle, length); + } + else if(y1 > y2) + setAngle(x1, y1, (float) Math.PI * 1.5f, length); + else if(y1 < y2) + setAngle(x1, y1, (float) Math.PI * 0.5f, length); + else + setAngle(x1, y1, 0, 0); + } + + public void setPoints(Vector3f p1, Vector3f p2) { + setPoints(p1.x, p1.y, p2.x, p2.y); + } + + public void setThickness(float thickness) { + this.thickness = thickness; + } + + public void setDepth(float z) { + position.z = z; + } + + public void setColor(float r, float g, float b, float a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } +} diff --git a/src/com/gnarly/engine/model/Rect.java b/src/com/gnarly/engine/model/Rect.java new file mode 100644 index 0000000..ad3f88d --- /dev/null +++ b/src/com/gnarly/engine/model/Rect.java @@ -0,0 +1,104 @@ +package com.gnarly.engine.model; + +import org.joml.Vector2f; +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; + +public class Rect { + + protected static Vao vao; + + protected Camera camera; + + protected float width, height; + protected Vector3f position; + protected float rotation, scale; + protected boolean gui; + + protected Rect(Camera camera, float x, float y, float z, float width, float height, float rotation, boolean gui) { + this.camera = camera; + this.width = width; + this.height = height; + position = new Vector3f(x, y, z); + scale = 1; + this.rotation = rotation; + this.gui = gui; + if(vao == null) { + float vertices[] = { + 1, 0, 0, // Top left + 1, 1, 0, // Bottom left + 0, 1, 0, // Bottom right + 0, 0, 0 // Top right + }; + int indices[] = { + 0, 1, 3, + 1, 2, 3 + }; + float[] texCoords = { + 1, 0, + 1, 1, + 0, 1, + 0, 0 + }; + vao = new Vao(vertices, indices); + vao.addAttrib(texCoords, 2); + } + } + + public float getX() { + return position.x; + } + + public float getY() { + return position.y; + } + + public float getWidth() { + return width; + } + + public float getHeight() { + return height; + } + + public void set(float x, float y, float width, float height) { + position.x = x; + position.y = y; + this.width = width; + this.height = height; + } + + public void setWidth(float width) { + this.width = width; + } + + public void setHeight(float height) { + this.height = height; + } + + public void setPosition(float x, float y, float z) { + position.set(x, y, z); + } + + public void setPosition(Vector2f position) { + this.position.x = position.x; + this.position.y = position.y; + } + + public void translate(float x, float y, float z) { + position.add(x, y, z); + } + + public void setRotation(float angle) { + rotation = angle; + } + + public void rotate(float angle) { + rotation += angle; + } + + public void setScale(float scale) { + this.scale = scale; + } +} diff --git a/src/com/gnarly/engine/model/TexRect.java b/src/com/gnarly/engine/model/TexRect.java new file mode 100644 index 0000000..1b6f779 --- /dev/null +++ b/src/com/gnarly/engine/model/TexRect.java @@ -0,0 +1,30 @@ +package com.gnarly.engine.model; + +import org.joml.Matrix4f; +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.shaders.Shader; +import com.gnarly.engine.shaders.Shader2t; +import com.gnarly.engine.texture.Texture; + +public class TexRect extends Rect { + + private Texture texture; + private Shader2t shader = Shader.SHADER2T; + + public TexRect(Camera camera, String path, float x, float y, float z, float width, float height, float rotation, boolean gui) { + super(camera, x, y, z, width, height, rotation, gui); + texture = new Texture(path); + } + + public void render() { + texture.bind(); + shader.enable(); + Matrix4f cmat = gui ? camera.getProjection() : camera.getMatrix(); + shader.setMVP(cmat.translate(position.add(width * scale / 2, height * scale / 2, 0, new Vector3f())).rotateZ(rotation * 3.1415927f / 180).scale(width * scale, height * scale, 1).translate(-0.5f, -0.5f, 0)); + vao.render(); + shader.disable(); + texture.unbind(); + } +} diff --git a/src/com/gnarly/engine/model/Vao.java b/src/com/gnarly/engine/model/Vao.java new file mode 100644 index 0000000..da101be --- /dev/null +++ b/src/com/gnarly/engine/model/Vao.java @@ -0,0 +1,63 @@ +package com.gnarly.engine.model; + +import static org.lwjgl.opengl.GL11.GL_FLOAT; +import static org.lwjgl.opengl.GL11.GL_TRIANGLES; +import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT; +import static org.lwjgl.opengl.GL11.glDrawElements; +import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER; +import static org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER; +import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW; +import static org.lwjgl.opengl.GL15.glBindBuffer; +import static org.lwjgl.opengl.GL15.glBufferData; +import static org.lwjgl.opengl.GL15.glDeleteBuffers; +import static org.lwjgl.opengl.GL15.glGenBuffers; +import static org.lwjgl.opengl.GL20.glDisableVertexAttribArray; +import static org.lwjgl.opengl.GL20.glEnableVertexAttribArray; +import static org.lwjgl.opengl.GL20.glVertexAttribPointer; +import static org.lwjgl.opengl.GL30.glBindVertexArray; +import static org.lwjgl.opengl.GL30.glDeleteVertexArrays; +import static org.lwjgl.opengl.GL30.glGenVertexArrays; + +public class Vao { + + private int numAttribs = 0; + + private int vao, ibo, count; + + private int[] vbos = new int[15]; + + public Vao(float[] vertices, int[] indices) { + vao = glGenVertexArrays(); + glBindVertexArray(vao); + addAttrib(vertices, 3); + ibo = glGenBuffers(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW); + count = indices.length; + } + + public void addAttrib(float[] data, int size) { + int vbo = glGenBuffers(); + vbos[numAttribs] = vbo; + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, data, GL_STATIC_DRAW); + glVertexAttribPointer(numAttribs, size, GL_FLOAT, false, 0, 0); + ++numAttribs; + } + + public void render() { + glBindVertexArray(vao); + for(int i = 0; i < numAttribs; ++i) + glEnableVertexAttribArray(i); + glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, 0); + for(int i = 0; i < numAttribs; ++i) + glDisableVertexAttribArray(i); + } + + public void destroy() { + for(int vbo : vbos) + glDeleteBuffers(vbo); + glDeleteBuffers(ibo); + glDeleteVertexArrays(vao); + } +} diff --git a/src/com/gnarly/engine/shaders/LevelEffect.java b/src/com/gnarly/engine/shaders/LevelEffect.java new file mode 100644 index 0000000..1077844 --- /dev/null +++ b/src/com/gnarly/engine/shaders/LevelEffect.java @@ -0,0 +1,99 @@ +package com.gnarly.engine.shaders; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Scanner; + +import org.joml.Vector4f; + +public class LevelEffect { + + private double length; + private Subeffect[] effects; + + public LevelEffect(String path) { + try { + Scanner scanner = new Scanner(new FileInputStream(new File(path))); + int numEffects = scanner.nextInt(); + effects = new Subeffect[numEffects]; + for (int i = 0; i < effects.length; i++) { + double lLength = scanner.nextDouble(); + boolean rgb = scanner.nextBoolean(); + length += lLength; + effects[i] = new Subeffect( + lLength, rgb, scanner.nextBoolean(), scanner.nextFloat(), scanner.nextFloat(), + new Vector4f(scanner.nextFloat() / (rgb ? 1 : 360f), scanner.nextFloat(), scanner.nextFloat(), scanner.nextFloat()), + new Vector4f(scanner.nextFloat() / (rgb ? 1 : 360f), scanner.nextFloat(), scanner.nextFloat(), scanner.nextFloat()), + new Vector4f(scanner.nextFloat() / (rgb ? 1 : 360f), scanner.nextFloat(), scanner.nextFloat(), scanner.nextFloat()), + new Vector4f(scanner.nextFloat() / (rgb ? 1 : 360f), scanner.nextFloat(), scanner.nextFloat(), scanner.nextFloat()) + ); + } + scanner.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public EffectPayload getPayload(double time) { + double rtime = time % length; + for (int i = 0; rtime > 0; ++i) { + rtime -= effects[i].getLength(); + if (rtime <= 0) + return effects[i].getPayload(rtime + effects[i].getLength()); + } + //Should never reach here + System.out.println("Program? Here!? Ha! Impossible! No program can make it pass the payload retrieval loop!"); + return null; + } + + private class Subeffect { + + private double length; + private boolean rgb, loop; + private float timeScale, freq; + private Vector4f c1, c2, c3, c4; + + public Subeffect(double length, boolean rgb, boolean loop, float timeScale, float freq, Vector4f color1, Vector4f color2, Vector4f color3, Vector4f color4) { + this.length = length; + this.rgb = rgb; + this.loop = loop; + this.timeScale = timeScale; + this.freq = freq; + c1 = color1; + c2 = color2; + c3 = color3; + c4 = color4; + } + + public EffectPayload getPayload(double time) { + float percent = (float) (time / length); + return new EffectPayload( + c1.add(c3.sub(c1, new Vector4f()).mul(percent), new Vector4f()), + c2.add(c4.sub(c2, new Vector4f()).mul(percent), new Vector4f()), + (float) (timeScale * time / length), freq, rgb, loop + ); + } + + public double getLength() { + return length; + } + }; + + public class EffectPayload { + + public Vector4f c1; + public Vector4f c2; + public float time, freq; + public boolean rgb, loop; + + public EffectPayload(Vector4f color1, Vector4f color2, float time, float freq, boolean rgb, boolean loop) { + this.c1 = color1; + this.c2 = color2; + this.time = time; + this.freq = freq; + this.rgb = rgb; + this.loop = loop; + } + }; +} diff --git a/src/com/gnarly/engine/shaders/Shader.java b/src/com/gnarly/engine/shaders/Shader.java new file mode 100644 index 0000000..a6330f5 --- /dev/null +++ b/src/com/gnarly/engine/shaders/Shader.java @@ -0,0 +1,101 @@ +package com.gnarly.engine.shaders; + +import static org.lwjgl.opengl.GL20.GL_COMPILE_STATUS; +import static org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER; +import static org.lwjgl.opengl.GL20.GL_VERTEX_SHADER; +import static org.lwjgl.opengl.GL20.glAttachShader; +import static org.lwjgl.opengl.GL20.glCompileShader; +import static org.lwjgl.opengl.GL20.glCreateProgram; +import static org.lwjgl.opengl.GL20.glCreateShader; +import static org.lwjgl.opengl.GL20.glDeleteProgram; +import static org.lwjgl.opengl.GL20.glDeleteShader; +import static org.lwjgl.opengl.GL20.glDetachShader; +import static org.lwjgl.opengl.GL20.glGetShaderInfoLog; +import static org.lwjgl.opengl.GL20.glGetShaderi; +import static org.lwjgl.opengl.GL20.glGetUniformLocation; +import static org.lwjgl.opengl.GL20.glLinkProgram; +import static org.lwjgl.opengl.GL20.glShaderSource; +import static org.lwjgl.opengl.GL20.glUniformMatrix4fv; +import static org.lwjgl.opengl.GL20.glUseProgram; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +import org.joml.Matrix4f; + +public abstract class Shader { + + public static Shader2c SHADER2C; + public static Shader2le SHADER2LE; + public static Shader2t SHADER2T; + + protected int program; + + protected int mvpLoc; + + protected Shader(String vertPath, String fragPath) { + program = glCreateProgram(); + + int vert = loadShader(vertPath, GL_VERTEX_SHADER); + int frag = loadShader(fragPath, GL_FRAGMENT_SHADER); + + glAttachShader(program, vert); + glAttachShader(program, frag); + + glLinkProgram(program); + + glDetachShader(program, vert); + glDetachShader(program, frag); + + glDeleteShader(vert); + glDeleteShader(frag); + + mvpLoc = glGetUniformLocation(program, "mvp"); + } + + private int loadShader(String path, int type) { + StringBuilder file = new StringBuilder(); + try { + BufferedReader reader = new BufferedReader(new FileReader(new File(path))); + String line; + while((line = reader.readLine()) != null) + file.append(line + '\n'); + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + String source = file.toString(); + int shader = glCreateShader(type); + glShaderSource(shader, source); + glCompileShader(shader); + if(glGetShaderi(shader, GL_COMPILE_STATUS) != 1) + throw new RuntimeException("Failed to compile shader: " + path + "! " + glGetShaderInfoLog(shader)); + return shader; + } + + protected abstract void getUniforms(); + + public void setMVP(Matrix4f matrix) { + glUniformMatrix4fv(mvpLoc, false, matrix.get(new float[16])); + } + + public void enable() { + glUseProgram(program); + } + + public void disable() { + glUseProgram(0); + } + + public void destroy() { + glDeleteProgram(program); + } + + public static void init() { + SHADER2C = new Shader2c(); + SHADER2LE = new Shader2le(); + SHADER2T = new Shader2t(); + } +} diff --git a/src/com/gnarly/engine/shaders/Shader2c.java b/src/com/gnarly/engine/shaders/Shader2c.java new file mode 100644 index 0000000..497910d --- /dev/null +++ b/src/com/gnarly/engine/shaders/Shader2c.java @@ -0,0 +1,22 @@ +package com.gnarly.engine.shaders; + +import static org.lwjgl.opengl.GL20.*; + +public class Shader2c extends Shader { + + int colorLoc; + + protected Shader2c() { + super("res/shaders/s2c/vert.gls", "res/shaders/s2c/frag.gls"); + getUniforms(); + } + + @Override + protected void getUniforms() { + colorLoc = glGetUniformLocation(program, "iColor"); + } + + public void setColor(float r, float g, float b, float a) { + glUniform4f(colorLoc, r, g, b, a); + } +} diff --git a/src/com/gnarly/engine/shaders/Shader2le.java b/src/com/gnarly/engine/shaders/Shader2le.java new file mode 100644 index 0000000..28eab07 --- /dev/null +++ b/src/com/gnarly/engine/shaders/Shader2le.java @@ -0,0 +1,39 @@ +package com.gnarly.engine.shaders; + +import static org.lwjgl.opengl.GL20.glGetUniformLocation; +import static org.lwjgl.opengl.GL20.glUniform1f; +import static org.lwjgl.opengl.GL20.glUniform1i; +import static org.lwjgl.opengl.GL20.glUniform4f; + +import com.gnarly.game.Main; + +public class Shader2le extends Shader { + + int color1Loc, color2Loc, timeLoc, rgbLoc, loopLoc, freqLoc, texLoc; + + protected Shader2le() { + super("res/shaders/s2le/vert.gls", "res/shaders/s2le/frag.gls"); + getUniforms(); + } + + @Override + protected void getUniforms() { + color1Loc = glGetUniformLocation(program, "color1"); + color2Loc = glGetUniformLocation(program, "color2"); + timeLoc = glGetUniformLocation(program, "time"); + rgbLoc = glGetUniformLocation(program, "rgb"); + loopLoc = glGetUniformLocation(program, "loop"); + freqLoc = glGetUniformLocation(program, "freq"); + texLoc = glGetUniformLocation(program, "textured"); + } + + public void setEffect(LevelEffect.EffectPayload payload, boolean textured) { + glUniform4f(color1Loc, payload.c1.x, payload.c1.y, payload.c1.z, payload.c1.w); + glUniform4f(color2Loc, payload.c2.x, payload.c2.y, payload.c2.z, payload.c2.w); + glUniform1f(timeLoc, payload.time); + glUniform1f(freqLoc, payload.freq); + glUniform1i(rgbLoc, payload.rgb ? 1 : 0); + glUniform1i(loopLoc, payload.loop ? 1 : 0); + glUniform1i(texLoc, textured ? 1 : 0); + } +} diff --git a/src/com/gnarly/engine/shaders/Shader2t.java b/src/com/gnarly/engine/shaders/Shader2t.java new file mode 100644 index 0000000..9e6d722 --- /dev/null +++ b/src/com/gnarly/engine/shaders/Shader2t.java @@ -0,0 +1,11 @@ +package com.gnarly.engine.shaders; + +public class Shader2t extends Shader { + + protected Shader2t() { + super("res/shaders/s2t/vert.gls", "res/shaders/s2t/frag.gls"); + } + + @Override + protected void getUniforms() {} +} \ No newline at end of file diff --git a/src/com/gnarly/engine/texture/Texture.java b/src/com/gnarly/engine/texture/Texture.java new file mode 100644 index 0000000..ef9662a --- /dev/null +++ b/src/com/gnarly/engine/texture/Texture.java @@ -0,0 +1,74 @@ +package com.gnarly.engine.texture; + +import static org.lwjgl.opengl.GL11.GL_CLAMP; +import static org.lwjgl.opengl.GL11.GL_NEAREST; +import static org.lwjgl.opengl.GL11.GL_RGBA; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T; +import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE; +import static org.lwjgl.opengl.GL11.glBindTexture; +import static org.lwjgl.opengl.GL11.glDeleteTextures; +import static org.lwjgl.opengl.GL11.glGenTextures; +import static org.lwjgl.opengl.GL11.glTexImage2D; +import static org.lwjgl.opengl.GL11.glTexParameterf; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; + +import javax.imageio.ImageIO; + +import org.lwjgl.BufferUtils; + +public class Texture { + + protected int id, width, height; + + public Texture(String path) { + try { + BufferedImage bi = ImageIO.read(new File(path)); + width = bi.getWidth(); + height = bi.getHeight(); + int[] pixels = bi.getRGB(0, 0, width, height, null, 0, width); + ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * 4); + + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + int pixel = pixels[i * width + j]; + buffer.put((byte)((pixel >> 16) & 0xFF)); // Red + buffer.put((byte)((pixel >> 8) & 0xFF)); // Green + buffer.put((byte)((pixel ) & 0xFF)); // Blue + buffer.put((byte)((pixel >> 24) & 0xFF)); // Alpha + } + } + buffer.flip(); + + id = glGenTextures(); + bind(); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + unbind(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void bind() { + glBindTexture(GL_TEXTURE_2D, id); + } + + public void unbind() { + glBindTexture(GL_TEXTURE_2D, 0); + } + + public void destroy() { + glDeleteTextures(id); + } +} diff --git a/src/com/gnarly/game/Countdown.java b/src/com/gnarly/game/Countdown.java new file mode 100644 index 0000000..02e280e --- /dev/null +++ b/src/com/gnarly/game/Countdown.java @@ -0,0 +1,60 @@ +package com.gnarly.game; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.model.ColRect; +import com.gnarly.engine.model.Rect; +import com.gnarly.engine.shaders.LevelEffect; +import com.gnarly.engine.shaders.Shader; +import com.gnarly.engine.shaders.Shader2le; +import com.gnarly.engine.texture.Texture; + +public class Countdown extends Rect { + + private Shader2le shader = Shader.SHADER2LE; + + private Camera camera; + + private LevelEffect effect; + private Texture[] nums; + + private double time; + + private ColRect dark; + + public Countdown(Camera camera, String path, float x, float y, float z, float width, float height) { + super(camera, x, y, z, width, height, 0, true); + this.camera = camera; + effect = new LevelEffect(path); + dark = new ColRect(camera, 0, 0, -0.05f, camera.getWidth(), camera.getHeight(), 0, 0, 0, 0.9f, true); + nums = new Texture[] { + new Texture("res/levels/all/one.png"), + new Texture("res/levels/all/two.png"), + new Texture("res/levels/all/three.png") + }; + } + + public void start() { + time = 3; + } + + public void render() { + dark.setOpacity(0.9f * (float) (Math.min(Math.pow(time, 0.33f), 1))); + dark.render(); + time -= Main.dtime; + if(time > 0) { + int num = (int) Math.ceil(time) - 1; + float scale = (float) (time - num) * 0.75f + 0.25f; + nums[num].bind(); + shader.enable(); + shader.setEffect(effect.getPayload(3 - time), true); + shader.setMVP(camera.getProjection().translate(position).translate((width - width * scale) / 2, (height - height * scale) / 2, 0).scale(width * scale, height * scale, 1)); + vao.render(); + shader.disable(); + nums[num].unbind(); + } + } + + public double getTime() { + return time; + } +} diff --git a/src/com/gnarly/game/EffectButton.java b/src/com/gnarly/game/EffectButton.java new file mode 100644 index 0000000..c89ab0c --- /dev/null +++ b/src/com/gnarly/game/EffectButton.java @@ -0,0 +1,78 @@ +package com.gnarly.game; + +import static org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_1; + +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; +import com.gnarly.engine.model.EffectRect; +import com.gnarly.engine.texture.Texture; + +public class EffectButton { + + public static final int + UNPRESSED = 0, + RELEASED = 1, + PRESSED = 2, + HELD = 3; + + private Window window; + private Camera camera; + + private EffectRect[] states; + + private float x, y, width, height; + + private int state, tex; + + public EffectButton(Window window, Camera camera, String texture, String eff1, String eff2, String eff3, float x, float y, float depth, float width, float height, boolean gui) { + this.window = window; + this.camera = camera; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + states = new EffectRect[3]; + states[0] = new EffectRect(camera, eff1, texture, x, y, depth, width, height, gui); + states[1] = new EffectRect(camera, eff2, texture, x, y, depth, width, height, gui); + states[2] = new EffectRect(camera, eff3, texture, x, y, depth, width, height, gui); + tex = 0; + state = 0; + } + + public void update() { + if(contains(window.getMouseCoords(camera))) { + if(window.mousePressed(GLFW_MOUSE_BUTTON_1) > 0) { + tex = 2; + if(state <= RELEASED) + state = PRESSED; + else + state = HELD; + } + else { + tex = 1; + if(state >= PRESSED) + state = RELEASED; + else + state = UNPRESSED; + } + } + else { + tex = 0; + state = UNPRESSED; + } + } + + public void render() { + states[tex].render(); + } + + public boolean contains(Vector3f coords) { + return coords.x >= x && coords.y >= y && coords.x < x + width && coords.y < y + height; + } + + public int getState() { + return state; + } +} diff --git a/src/com/gnarly/game/GamePanel.java b/src/com/gnarly/game/GamePanel.java new file mode 100644 index 0000000..5060ebb --- /dev/null +++ b/src/com/gnarly/game/GamePanel.java @@ -0,0 +1,110 @@ +package com.gnarly.game; + +import static org.lwjgl.glfw.GLFW.GLFW_KEY_SPACE; + +import java.io.File; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; +import com.gnarly.engine.model.ColRect; +import com.gnarly.engine.model.EffectRect; + +public class GamePanel { + + private Window window; + private Camera camera; + + private Countdown countdown; + + private Map[] maps; + private int curLevel = 0; + + private EffectButton retry, next; + private EffectRect sretry, snext; + private ColRect dark; + + private int state = 0; + + public GamePanel(Window window, Camera camera) { + this.window = window; + this.camera = camera; + countdown = new Countdown(camera, "res/levels/all/countdown.fx", camera.getWidth() / 2 - 5, camera.getHeight() / 2 - 5, 0, 10, 10); + countdown.start(); + int numLevels = new File("res/levels").list().length - 1; + maps = new Map[numLevels]; + for (int i = 0; i < numLevels; i++) + maps[i] = new Map(window, camera, "res/levels/level" + (i + 1)); + next = new EffectButton(window, camera, "res/levels/all/next/next.png", "res/levels/all/next/unpressed.fx", "res/levels/all/next/hovered.fx", "res/levels/all/next/pressed.fx", (camera.getWidth() - 15) / 2, (camera.getHeight() - 2) / 2, 0, 15, 2, true); + snext = new EffectRect(camera, "res/levels/all/next/unpressed.fx", "res/levels/all/next/space.png", (camera.getWidth() - 9.7857142f) / 2, (camera.getHeight() - 1) / 2 + 2.25f, 0, 9.7857142f, 1, true); + retry = new EffectButton(window, camera, "res/levels/all/retry/retry.png", "res/levels/all/retry/unpressed.fx", "res/levels/all/retry/hovered.fx", "res/levels/all/retry/pressed.fx", (camera.getWidth() - 10) / 2, (camera.getHeight() - 2) / 2, 0, 10, 2, true); + sretry = new EffectRect(camera, "res/levels/all/retry/unpressed.fx", "res/levels/all/retry/space.png", (camera.getWidth() - 8.7857142f) / 2, (camera.getHeight() - 1) / 2 + 2.25f, 0, 8.7857142f, 1, true); + dark = new ColRect(camera, 0, 0, -0.05f, camera.getWidth(), camera.getHeight(), 0, 0, 0, 0.5f, true); + } + + public void update() { + if (state == 1) { + maps[curLevel].update(); + state = maps[curLevel].checkState(); + } + else if(state == 2) { + retry.update(); + if(retry.getState() == EffectButton.RELEASED || window.keyPressed(GLFW_KEY_SPACE) == 1) { + countdown.start(); + state = 0; + maps[curLevel].reload(); + } + } + else if(state == 3) { + next.update(); + if(next.getState() == EffectButton.RELEASED || window.keyPressed(GLFW_KEY_SPACE) == 1) { + countdown.start(); + state = 0; + ++curLevel; + + if(curLevel == maps.length) { + curLevel = 0; + state = 4; + } + maps[curLevel].reload(); + } + } + else if(countdown.getTime() < 0) { + countdown.start(); + state = 1; + maps[curLevel].start(); + } + } + + public void render() { + maps[curLevel].render(); + if(state == 0) + countdown.render(); + else if(state == 2) { + dark.render(); + retry.render(); + float scale = (float) (Math.sin(2f / 4f * Math.PI * Main.ttime) / 8 + 0.875f); + sretry.setPosition((camera.getWidth() - sretry.getWidth() * scale) / 2, (camera.getHeight() - sretry.getHeight() * scale) / 2 + 2.25f, 0); + sretry.setScale(scale); + sretry.render(); + } + else if(state == 3) { + dark.render(); + next.render(); + float scale = (float) (Math.sin(2f / 4f * Math.PI * Main.ttime) / 8 + 0.875f); + snext.setPosition((camera.getWidth() - snext.getWidth() * scale) / 2, (camera.getHeight() - snext.getHeight() * scale) / 2 + 2.25f, 0); + snext.setScale(scale); + snext.render(); + } + } + + public int getState() { + int temp = state; + if(state == 4) + state = 0; + return 1 - (int) (temp / 4); + } + + public void setActive() { + maps[curLevel].camToSnake(); + } +} \ No newline at end of file diff --git a/src/com/gnarly/game/Main.java b/src/com/gnarly/game/Main.java new file mode 100644 index 0000000..dde672c --- /dev/null +++ b/src/com/gnarly/game/Main.java @@ -0,0 +1,84 @@ +package com.gnarly.game; + +import static org.lwjgl.glfw.GLFW.GLFW_KEY_ESCAPE; + +import com.gnarly.engine.audio.ALManagement; +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; +import com.gnarly.engine.shaders.Shader; + +public class Main { + + private int FPS = 60; + + public static double dtime; + public static double ttime; + + private ALManagement al; + + private Window window; + private Camera camera; + + private Menu menu; + private GamePanel panel; + + private int state = 0; + + public void start() { + long curTime, pastTime, startTime, nspf = 1000000000 / FPS; + init(); + pastTime = System.nanoTime(); + startTime = pastTime; + while(!window.shouldClose()) { + curTime = System.nanoTime(); + if(curTime - pastTime > nspf) { + dtime = (curTime - pastTime) / 1000000000d; + ttime = (curTime - startTime) / 1000000000d; + update(); + render(); + pastTime = curTime; + } + } + al.destroy(); + Window.terminate(); + } + + private void init() { + al = new ALManagement(); + window = new Window("Snake++", true); + camera = new Camera(32, 18); + Shader.init(); + menu = new Menu(window, camera); + panel = new GamePanel(window, camera); + } + + private void update() { + window.update(); + if(window.keyPressed(GLFW_KEY_ESCAPE) == 1) + window.close(); + if(state == 0) { + menu.update(); + state = menu.getState(); + if(state == 1) + panel.setActive(); + } + else { + panel.update(); + state = panel.getState(); + } + camera.update(); + } + + private void render() { + window.clear(); + if(state == 0) + menu.render(); + else + panel.render(); + window.swap(); + } + + public static void main(String[] args) { + new Main().start(); + } +} diff --git a/src/com/gnarly/game/Map.java b/src/com/gnarly/game/Map.java new file mode 100644 index 0000000..32db904 --- /dev/null +++ b/src/com/gnarly/game/Map.java @@ -0,0 +1,245 @@ +package com.gnarly.game; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Scanner; + +import javax.imageio.ImageIO; + +import org.joml.Vector2f; + +import com.gnarly.engine.audio.Sound; +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; +import com.gnarly.engine.model.EffectRect; + +public class Map { + + private static final int + TYPE_EMPTY = 0, + TYPE_WALL = 1, + TYPE_START = 2, + TYPE_END = 3, + TYPE_LENGTH = 4, + TYPE_SPEED = 5; + + private EffectRect border, speedIcon, lengthIcon; + + private Window window; + private Camera camera; + + private Sound sound; + + private String level; + + private int width, height; + private int[][] map; + + private Snake snake; + + private int speed = 0; + private double time = 0; + + private int state = 1; + + public Map(Window window, Camera camera, String level) { + this.window = window; + this.camera = camera; + this.level = level; + border = new EffectRect(camera, level + "/effect.fx", 0, 0, -0.1f, 1, 1, false); + speedIcon = new EffectRect(camera, level + "/effect.fx", "res/levels/all/speed.png", 0, 0, -0.1f, 1, 1, false); + lengthIcon = new EffectRect(camera, level + "/effect.fx", "res/levels/all/length.png", 0, 0, -0.1f, 1, 1, false); + snake = new Snake(window, camera); + sound = new Sound(level + "/music.wav"); + loadProps(level + "/data.prop"); + loadMap(level + "/level.png"); + } + + public void update() { + time += Main.dtime; + if(time >= 1f / speed) { + snake.update(true); + time = 0; + } + else + snake.update(false); + if(!snake.check(width, height)) + state = 2; + Vector2f head = snake.getHead(); + int headType = map[(int) head.x][(int) head.y]; + switch (headType) { + case TYPE_WALL: + state = 2; + break; + case TYPE_END: + state = 3; + border.setEffect("res/levels/all/victory.fx"); + case TYPE_LENGTH: + map[(int) head.x][(int) head.y] = TYPE_EMPTY; + snake.lengthen(10); + break; + case TYPE_SPEED: + map[(int) head.x][(int) head.y] = TYPE_EMPTY; + speed += 2; + break; + } + setCamera(snake.getFuture((float) (time * speed))); + } + + private void setCamera(Vector2f position) { + camera.setCenter(position.x, position.y); + if(camera.getX() < 0) + camera.setX(0); + else if(camera.getX() + camera.getWidth() > width) + camera.setX(width - camera.getWidth()); + if(camera.getY() < 0) + camera.setY(0); + else if(camera.getY() + camera.getHeight() > height) + camera.setY(height - camera.getHeight()); + } + + public void camToSnake() { + setCamera(snake.getHead()); + } + + public void reload() { + loadProps(level + "/data.prop"); + loadMap(level + "/level.png"); + border.setEffect(level + "/effect.fx"); + camToSnake(); + state = 1; + } + + public int checkCamera() { + int ret = 0; + if (camera.getX() < 0 || camera.getX() + camera.getWidth() > width) + ret += 1; + if (camera.getY() < 0 || camera.getY() + camera.getHeight() > height) + ret += 2; + return ret; + } + + public void start() { + sound.play(true); + } + + public void stop() { + sound.stop(); + } + + public void render() { + snake.render((float) (time * speed)); + int minX = (int) Math.max(camera.getX(), 0); + int minY = (int) Math.max(camera.getY(), 0); + for (int i = minX; i < Math.min(minX + camera.getWidth() + 1, width); i++) { + for (int j = minY; j < Math.min(minY + camera.getHeight() + 1, height); j++) { + switch (map[i][j]) { + case TYPE_WALL: + if (i == 0 || j == 0 || map[i - 1][j] != TYPE_WALL || map[i][j - 1] != TYPE_WALL || map[i - 1][j - 1] != TYPE_WALL) { // Top Left -1, -1 + border.set(i, j, 0.1f, 0.1f); + border.render(); + } + if (j == 0 || map[i][j - 1] != TYPE_WALL) { // Top Middle 0, -1 + border.set(i + 0.1f, j, 0.8f, 0.1f); + border.render(); + } + if (i == width - 1 || j == 0 || map[i + 1][j] != TYPE_WALL || map[i][j - 1] != TYPE_WALL || map[i + 1][j - 1] != TYPE_WALL) { // Top Right +1, -1 + border.set(i + 0.9f, j, 0.1f, 0.1f); + border.render(); + } + if (i == 0 || map[i - 1][j] != TYPE_WALL) { // Middle Left -1, 0 + border.set(i, j + 0.1f, 0.1f, 0.8f); + border.render(); + } + if (i == width - 1 || map[i + 1][j] != TYPE_WALL) { // Middle Right +1, 0 + border.set(i + 0.9f, j + 0.1f, 0.1f, 0.8f); + border.render(); + } + if (i == 0 || j == height - 1 || map[i - 1][j] != TYPE_WALL || map[i][j + 1] != TYPE_WALL || map[i - 1][j + 1] != TYPE_WALL) { // Bottom Left -1, +1 + border.set(i, j + 0.9f, 0.1f, 0.1f); + border.render(); + } + if (j == height - 1 || map[i][j + 1] != TYPE_WALL) { // Bottom Middle 0, +1 + border.set(i + 0.1f, j + 0.9f, 0.8f, 0.1f); + border.render(); + } + if (i == width - 1 || j == height - 1 || map[i + 1][j] != TYPE_WALL || map[i][j + 1] != TYPE_WALL || map[i + 1][j + 1] != TYPE_WALL) { // Bottom Right +1, +1 + border.set(i + 0.9f, j + 0.9f, 0.1f, 0.1f); + border.render(); + } + break; + case TYPE_END: + border.set(i, j, 1, 1); + border.render(); + break; + case TYPE_SPEED: + speedIcon.set(i, j, 1, 1); + speedIcon.render(); + break; + case TYPE_LENGTH: + lengthIcon.set(i, j, 1, 1); + lengthIcon.render(); + break; + } + } + } + } + + public int checkState() { + if (state == 2) + border.setEffect("res/levels/all/defeat.fx"); + if (state != 1) + sound.stop(); + return state; + } + + private void loadProps(String path) { + try { + Scanner scanner = new Scanner(new FileInputStream(new File(path))); + speed = scanner.nextInt(); + snake.lengthen(scanner.nextInt() - 1); + scanner.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void loadMap(String path) { + try { + InputStream stream = new FileInputStream(new File(path)); + BufferedImage level = ImageIO.read(stream); + stream.close(); + width = level.getWidth() + 2; + height = level.getHeight() + 2; + map = new int[width][height]; + for (int i = 0; i < map.length; i++) { + for (int j = 0; j < map[0].length; j++) { + if(i == 0 || j == 0 || i == width - 1 || j == height - 1) + map[i][j] = TYPE_WALL; + else { + int pixel = level.getRGB(i - 1, j - 1); + if (pixel == 0xffffffff) + map[i][j] = TYPE_WALL; + else if (pixel >= 0xff00ff00 && pixel <= 0xff00ff03) { + map[i][j] = TYPE_START; + snake.reset(i, j, Snake.DIRS[pixel & 0x03]); + } + else if (pixel == 0xffff0000) + map[i][j] = TYPE_END; + else if (pixel == 0xff0000FF) + map[i][j] = TYPE_LENGTH; + else if (pixel == 0xffff7f00) + map[i][j] = TYPE_SPEED; + else + map[i][j] = TYPE_EMPTY; + } + } + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/com/gnarly/game/Menu.java b/src/com/gnarly/game/Menu.java new file mode 100644 index 0000000..9f4d25f --- /dev/null +++ b/src/com/gnarly/game/Menu.java @@ -0,0 +1,61 @@ +package com.gnarly.game; + +import org.joml.Vector3f; + +import com.gnarly.engine.audio.Sound; +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; +import com.gnarly.engine.model.EffectRect; + +public class Menu { + + private Window window; + private Camera camera; + + private Map map; + private EffectRect logo; + private EffectButton play; + + private Vector3f camVel; + private int state = 0; + + public Menu(Window window, Camera camera) { + this.window = window; + this.camera = camera; + logo = new EffectRect(camera, "res/menu/logo.fx", "res/menu/logo.png", (camera.getWidth() - 20) / 2, 0, 0, 20, 6.3414634f, true); + map = new Map(window, camera, "res/menu"); + map.start(); + play = new EffectButton(window, camera, "res/menu/play.png", "res/menu/logo.fx", "res/menu/hovered.fx", "res/menu/pressed.fx", (camera.getWidth() - 8) / 2, 9, 0, 8, 2.7272727f, true); + camVel = new Vector3f((float) (Math.random() * 2 - 1), (float) (Math.random() * 2 - 1), 0); + camVel.normalize(); + camVel.mul(3); + camera.setPosition(new Vector3f(3, 3, 0)); + } + + public void update() { + camera.translate(camVel.mul((float) Main.dtime, new Vector3f())); + int change = map.checkCamera(); + if((change & 0x01) == 1) + camVel.x = -camVel.x; + if((change & 0x02) == 2) + camVel.y = -camVel.y; + play.update(); + if(play.getState() == EffectButton.RELEASED) + state = 1; + } + + public void render() { + map.render(); + logo.render(); + play.render(); + } + + public int getState() { + int temp = state; + if (state != 0) { + map.stop(); + state = 0; + } + return temp; + } +} diff --git a/src/com/gnarly/game/Snake.java b/src/com/gnarly/game/Snake.java new file mode 100644 index 0000000..eddbaf2 --- /dev/null +++ b/src/com/gnarly/game/Snake.java @@ -0,0 +1,135 @@ +package com.gnarly.game; + +import static org.lwjgl.glfw.GLFW.GLFW_KEY_A; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_D; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_DOWN; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_RIGHT; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_S; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_UP; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_W; + +import java.util.LinkedList; + +import org.joml.Vector2f; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; +import com.gnarly.engine.model.ColRect; + +public class Snake { + + public static final Vector2f + DIR_UP = new Vector2f( 0, -1), + DIR_DOWN = new Vector2f( 0, 1), + DIR_LEFT = new Vector2f(-1, 0), + DIR_RIGHT = new Vector2f( 1, 0); + + public static final int + DIR_UP_AR = 0, + DIR_DOWN_AR = 1, + DIR_LEFT_AR = 2, + DIR_RIGHT_AR = 3; + + public static final Vector2f[] + DIRS = { DIR_UP, DIR_DOWN, DIR_LEFT, DIR_RIGHT }; + + private static ColRect rect = null; + + private Window window; + private Camera camera; + + private Vector2f dir, banned = null, future; + private LinkedList snake = new LinkedList(); + + private int addLength = 0; + + public Snake(Window window, Camera camera) { + this.window = window; + this.camera = camera; + if(rect == null) + rect = new ColRect(camera, 0, 0, -0.08f, 1, 1, 0, 1, 0, 1, false); + } + + public void update(boolean full) { + if (full) { + snake.add(0, snake.get(0).add(future, new Vector2f())); + if(addLength == 0) + snake.removeLast(); + else + --addLength; + future = dir; + banned = future; + } + if(window.keyPressed(GLFW_KEY_LEFT) > 0 || window.keyPressed(GLFW_KEY_A) > 0 && banned != DIR_RIGHT) + dir = DIR_LEFT; + else if(window.keyPressed(GLFW_KEY_RIGHT) > 0 || window.keyPressed(GLFW_KEY_D) > 0 && banned != DIR_LEFT) + dir = DIR_RIGHT; + else if(window.keyPressed(GLFW_KEY_UP) > 0 || window.keyPressed(GLFW_KEY_W) > 0 && banned != DIR_DOWN) + dir = DIR_UP; + else if(window.keyPressed(GLFW_KEY_DOWN) > 0 || window.keyPressed(GLFW_KEY_S) > 0 && banned != DIR_UP) + dir = DIR_DOWN; + } + + public boolean check(int width, int height) { + Vector2f head = snake.get(0); + if (head.x < 0 || head.x == width || head.y < 0 || head.y == height) + return false; + for (int i = 1; i < snake.size(); i++) + if (head.equals(snake.get(i))) + return false; + return true; + } + + public void lengthen() { + ++addLength; + } + + public void lengthen(int length) { + addLength += length; + } + + public Vector2f getHead() { + return new Vector2f(snake.get(0)); + } + + public Vector2f getFuture() { + return snake.get(0).add(future, new Vector2f()); + } + + public Vector2f getFuture(float percent) { + return new Vector2f(snake.get(0).add(future.mul(percent, new Vector2f()), new Vector2f())); + } + + public boolean contains(Vector2f position) { + for (int i = 0; i < snake.size(); i++) + if(snake.get(i).equals(position)) + return true; + return false; + } + + public void render(float percent) { + if(addLength > 0) { + rect.setPosition(snake.getLast()); + rect.render(); + } + snake.add(0, snake.get(0).add(future, new Vector2f())); + for (int i = 1; i < snake.size(); i++) { + rect.setPosition(snake.get(i).add(snake.get(i - 1).sub(snake.get(i), new Vector2f()).mul(percent), new Vector2f())); + rect.render(); + if(i != snake.size() - 1 && snake.get(i - 1).x != snake.get(i + 1).x && snake.get(i - 1).y != snake.get(i + 1).y) { + rect.setPosition(snake.get(i)); + rect.render(); + } + } + snake.remove(0); + } + + public void reset(int x, int y, Vector2f dir) { + snake.clear(); + snake.add(new Vector2f(x, y)); + banned = dir; + this.dir = dir; + future = dir; + } +}