Compare commits

..

15 Commits

Author SHA1 Message Date
opfromthestart
71250104ea Better 3d falling
-Sand now can fall from and to the direction of gravity
-Registers every FallingBlock block to a different value. It doesnt
quite work though
-Removed unused code
2021-09-10 16:20:09 -04:00
opfromthestart
51752f95f9
Merge pull request #15 from opfromthestart/falling-block
Falling block
2021-08-23 13:35:58 -04:00
opfromthestart
175f092673 Fixed some stuff
-Added default gravity block check in server
-Some things I had to copy since i didnt merge right
-Adds all gravity blocks to FallingBlock list
-LogTop debug thing to check for good textures
-Some texture rendering(see above)
-Some control changes since I need to get to the edge quickly
2021-08-23 13:33:18 -04:00
opfromthestart
59129f95c9 Why
-Idk this has to be "Sand" and not "Test:Sand"
2021-08-22 14:04:42 -04:00
opfromthestart
efff41a6db Merge branch 'master' into falling-block 2021-08-22 14:03:31 -04:00
opfromthestart
30879a1241
Merge pull request #1 from OLEGSHA/master
Uhhh pull
2021-08-22 13:47:54 -04:00
opfromthestart
dccfcc9419 Better /Stuff
-Uses Coordinates a little in TestWorldGenerator. Ill do more eventually I think
-Better sprite getting for FallingBlocks
2021-08-03 15:05:05 -04:00
opfromthestart
c2a2cc074a Some Stuff to Fix Bugs
-Improved debug info of Fallingblock ticking
-Fixed unsynchronized access as per OLEGSHA
-Maybe better server side deletion of blocks
2021-08-03 14:45:36 -04:00
opfromthestart
e58007ea11 Format
Format
2021-06-10 17:09:24 -04:00
opfromthestart
ae2980c9de Bug Fixing and Performance
-Multiple null checks(It doesn't work without them)
-Checks to make sure entities are within loaded chunks
-Actual entity removal
2021-06-10 17:00:09 -04:00
opfromthestart
3879e5ffac Sand Towers Fall
-The listener in TestWorldGenerator updates any block above it if that block is a block that can be affected by gravity.
-Format happened(I forgot)
2021-06-10 15:56:15 -04:00
opfromthestart
47eb9fa5af Conservation of Matter
-Placing a Test:Sand block now deletes the block and summons a Test:FallingBlock in its place.
2021-06-10 14:08:35 -04:00
opfromthestart
bf49687ab6 Better performance maybe?
-Changed as many of the ClientState statements to context as I could.
-Only looks for a sand based update once per block update(I think it was twice before)
2021-06-10 12:50:51 -04:00
opfromthestart
b3ae829383 Almost All Works
-Added Set in TestEntityLogicFallingBlock to keep track of gravity blocks
  -Used this set in listener in TestWorldGenerator
-setInvisible and isDone() methods in TestEntityDataFallingBlock
  -Used to determine if the entity should be rendered/cared about in TestEntityRenderFallingBlock and TestEntityLogicFallingBlock
-Added more accurate Vec3i mod and div methods in TestEntityLogicFallingBlock
  *Change this to a better place
-TestEntityLogicFallingBlock actually places the block when the entity lands
-Better air block detection in TestWorldGenerator
*Still cannot erase the original placed block, not sure why.
2021-05-09 15:57:38 -04:00
opfromthestart
b374e9a736 Added FallingBlock Classes
-Added TestEntityDataFallingBlock class
  -Right now only supports Test:Sand
  -Kinda just copied from Statie
-Added TestEntityRenderFallingBlock
  -Used BlockRenderTexturedCube and TestEntityRenderStatie for this one
  -Has a setTexture method, but it needs improving
-Added TestEntityLogicFallingBlock class
  -Allows for a falling block to return to being a block.
  -The coordinates of the entity never move, even if it does ingame.
-In TestContent
  -Registers Test:FallingBlock
-In TestWorldGenerator
  -Adds listener for a sand block being placed
    -Listener replaces the block with a FallingBlock entity
    -It should also replace the block with air but it hasn't been working for me.
2021-05-04 20:29:06 -04:00
556 changed files with 5198 additions and 12802 deletions

2
.gitattributes vendored
View File

@ -6,4 +6,4 @@
* text=auto eol=lf
*.bat text eol=crlf
*.nsi text eol=crlf

View File

@ -1,49 +0,0 @@
name: Bug Report
description: Let us know about a problem
labels: [bug]
body:
- type: markdown
attributes:
value: |
Use this template to report identified problems. If the game suddenly crashed, and you need help identifying the cause of a crashreport, please use the Investigate Crashreport template instead.
**Do not forget to give your issue a descriptive title.**
- type: textarea
attributes:
label: Steps to reproduce
description: |
What did you do just before the problem appeared, or where can it be observed?
If the issue occurs unreliably, please estimate the probability of the crash.
placeholder: |
1. Look at a cow
2. Wait for the cow to look back
3. The cow turns away after a minute
The issue occurs approximately once every 10 attempts.
Player inventory must be empty. Does not occur in multiplayer. Occurred inside a virtual machine.
validations:
required: true
- type: textarea
attributes:
label: Expected behaviour
description: |
What should happen?
placeholder: |
The cow should stare back indefinitely, because obviously it should, and because comedy.
validations:
required: true
- type: textarea
attributes:
label: Other information
description: What else can you tell us about this bug?
validations:
required: false
- type: textarea
attributes:
label: Crashreport
description: If you have a relevant crashreport, paste the contents of the crashreport file here
render: text
validations:
required: false

View File

@ -1,5 +0,0 @@
blank_issues_enabled: true
contact_links:
- name: Official Progressia Discord
url: https://discord.gg/TWuXbVmX23
about: Ask developers or community members for help

View File

@ -1,41 +0,0 @@
name: Investigate Crashreport
description: Submit a crashreport to determine the problem
labels: [bug, crashreport]
body:
- type: markdown
attributes:
value: |
Use this template to submit crashreports for initial analisys. If you don't have a crashreport, or you have a good understanding of the underlying cause, please use the Bug Report template instead.
Crashreports can be found in `WORKING-DIRECTORY/crashreports` (take notice of the timestamp). `WORKING-DIRECTORY` is `C:\Users\<windows-user>\AppData\Roaming\Progressia` on Windows when using the installer.
**Do not forget to give your issue a descriptive title.**
- type: textarea
attributes:
label: Steps to reproduce
description: |
What did you do just before the crash? How could someone else reproduce it? What other context might be relevant?
If the issue occurs unreliably, please estimate the probability of the crash.
placeholder: |
1. Enter a new world
2. Turn around
3. Wait 5 minutes
4. Game crashes half of the time
Player inventory must be empty. Does not crash in multiplayer. Occurred inside a virtual machine.
validations:
required: true
- type: textarea
attributes:
label: Other information
description: What else can you tell us about this crashreport?
validations:
required: false
- type: textarea
attributes:
label: Crashreport
description: Paste the contents of the crashreport file here
render: text
validations:
required: true

View File

@ -1,29 +1,23 @@
/*
* Build logic for Progressia
* build.gradle
*
* Please refer to
*
* docs/building/BuildScriptReference.md
*
* for user reference.
* build.gradle for Progressia
*/
plugins {
id 'java'
// Apply the java-library plugin to add support for Java Library
id 'java-library'
// GrGit
// A JGit wrapper for Groovy used to access git commit info
id 'org.ajoberstar.grgit' version '4.1.1'
/*
* Uncomment the following line to enable the Eclipse plugin.
* This is only necessary if you don't use Buildship plugin from the IDE
*/
//id 'eclipse'
}
/*
* Configure Java version
*/
java {
/*
* We're Java 8 for now.
* Why? As of 2020, most users have Oracle Java, which only supports Java 8.
*/
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
@ -40,27 +34,16 @@ compileJava {
}
}
/*
* Set encoding
*/
compileJava {
options.encoding = 'utf8'
}
/*
* Dependencies
*/
repositories {
mavenCentral()
jcenter()
/*
* Windcorp Maven repository
* Specify Windcorp Maven repository
* Currently used by:
* - ru.windcorp.fork.io.github.java-graphics:glm:1.0.1
*/
@ -70,7 +53,7 @@ repositories {
dependencies {
// Google Guava
// A generic utilities library
implementation 'com.google.guava:guava:31.0.1-jre'
implementation 'com.google.guava:guava:30.0-jre'
// Trove4j
// Provides optimized Collections for primitive types
@ -83,311 +66,231 @@ dependencies {
// Log4j
// A logging library
implementation 'org.apache.logging.log4j:log4j-api:2.17.1'
implementation 'org.apache.logging.log4j:log4j-core:2.17.1'
implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.13.3'
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.13.3'
// JUnit
// A unit-testing library
testImplementation 'junit:junit:4.13.2'
testImplementation 'junit:junit:4.12'
// Also see LWJGL dependencies in build_logic/lwjgl.gradle
// See LWJGL dependencies below
}
/*
* Version resolution
* Progressia uses the following LWJGL libraries:
* - Core libraries
* - OpenGL
* - OpenAL
* - GLFW
* - STB
*/
import org.ajoberstar.grgit.*
/*
* LWJGL
* (auto-generated script)
* ((here be dragons))
*/
// Pattern: vMAJOR.MINOR.PATCH[-SUFFIX]
project.ext.tagFormat = /^v(\d+)\.(\d+)\.(\d+)(-[\w\-]*)?$/
import org.gradle.internal.os.OperatingSystem
String version_parseVersion(String tag, boolean increment) {
try {
project.ext.lwjglVersion = "3.2.3"
def data = (tag =~ tagFormat)[0]
switch (OperatingSystem.current()) {
case OperatingSystem.LINUX:
def osArch = System.getProperty("os.arch")
project.ext.lwjglNatives = osArch.startsWith("arm") || osArch.startsWith("aarch64")
? "natives-linux-${osArch.contains("64") || osArch.startsWith("armv8") ? "arm64" : "arm32"}"
: "natives-linux"
break
case OperatingSystem.MAC_OS:
project.ext.lwjglNatives = "natives-macos"
break
case OperatingSystem.WINDOWS:
project.ext.lwjglNatives = System.getProperty("os.arch").contains("64") ? "natives-windows" : "natives-windows-x86"
break
}
def major = data[1]
def minor = data[2]
def patch = data[3] as int
def suffix = data[4] ?: ''
dependencies {
implementation platform("org.lwjgl:lwjgl-bom:$lwjglVersion")
if (increment) {
def oldVersion = "$major.$minor.$patch$suffix"
patch++
def newVersion = "$major.$minor.$patch$suffix"
implementation "org.lwjgl:lwjgl"
implementation "org.lwjgl:lwjgl-glfw"
implementation "org.lwjgl:lwjgl-openal"
implementation "org.lwjgl:lwjgl-opengl"
implementation "org.lwjgl:lwjgl-stb"
logger.info "Version parsed from Git: $oldVersion, incremented to $newVersion"
return newVersion
} else {
def newVersion = "$major.$minor.$patch$suffix"
logger.info "Version parsed from Git: $newVersion"
return newVersion
runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives"
}
// LWJGL END
/*
* Tasks
*/
/*
* Additional native libraries specification
*/
project.ext.platforms = new HashSet<>()
task addNativeDependencies {
doFirst {
def archs = project.ext.platforms
switch (archs.size()) {
case 0:
println "Adding LWJGL native dependencies for local platform only:\n\t$lwjglNatives"
archs.add project.ext.lwjglNatives
break
case 1:
println "Adding LWJGL native dependencies for platform\n\t" + archs.get(0)
break
default:
println "Adding LWJGL native dependencies for platforms:\n\t" + archs.join("\n\t")
}
} catch (any) {
logger.warn "Could not parse version from tag \"$tag\""
return tag
if (project.ext.lwjglNatives.isEmpty()) println "WTF"
dependencies {
archs.each { arch ->
runtimeOnly "org.lwjgl:lwjgl::$arch"
runtimeOnly "org.lwjgl:lwjgl-glfw::$arch"
runtimeOnly "org.lwjgl:lwjgl-openal::$arch"
runtimeOnly "org.lwjgl:lwjgl-opengl::$arch"
runtimeOnly "org.lwjgl:lwjgl-stb::$arch"
}
}
}
}
Tag version_findRelevantTag(Grgit git) {
def tags = git.tag.list()
compileJava.mustRunAfter addNativeDependencies // Make sure runtimeOnly has not been resolved
def commits = [ git.head() ]
def visited = new HashSet<>()
while (true) {
if (commits.isEmpty()) return null
def nextCommits = new HashSet<>()
def formatSpecificationPrinted = false
for (def commit : commits) {
def tag = tags.findAll { it.commit == commit } ?.max { it.dateTime }
if (tag != null) {
if (tag.name ==~ tagFormat) {
return tag
} else {
if (!formatSpecificationPrinted) {
formatSpecificationPrinted = true
logger.info 'Expecting tag format: vMAJOR.MINOR.PATCH[-SUFFIX]'
task requestLinuxDependencies {
description 'Adds linux, linux-arm64 and linux-arm32 native libraries to built artifacts.'
doFirst {
project.ext.platforms.addAll(['natives-linux', 'natives-linux-arm64', 'natives-linux-arm32'])
}
logger.info 'Ignoring tag due to invalid format: {}', tag.name
}
task requestWindowsDependencies {
description 'Adds windows and windows-x86 native libraries to built artifacts.'
doFirst {
project.ext.platforms.addAll(['natives-windows', 'natives-windows-x86'])
}
}
nextCommits.addAll commit.parentIds.collect(git.resolve.&toCommit)
}
visited.addAll commits
nextCommits.removeAll visited
commits = nextCommits
}
task requestMacOSDependencies {
description 'Adds macos native libraries to built artifacts.'
doFirst {
project.ext.platforms.addAll(['natives-macos'])
}
}
task resolveVersion {
description 'Resolves version information from Git repository or project properties.'
def dependencySpecificationTasks = tasks.findAll { task -> task.name.startsWith('request') && task.name.endsWith('Dependencies') }
task requestCrossPlatformDependencies {
description 'Adds native libraries for all available platforms to built artifacts.'
dependsOn dependencySpecificationTasks
}
addNativeDependencies.mustRunAfter dependencySpecificationTasks
/*
* Determines if the provided dependency should be packaged
*/
def isDependencyRequested(String dep) {
if (dep.endsWith(".jar")) {
dep = dep.substring(0, dep.length() - ".jar".length())
}
return !dep.contains("natives-") ||
project.ext.platforms.contains(dep.substring(dep.indexOf("natives-"), dep.length()))
}
/*
* Manifest specification
*/
task specifyLocalManifest {
dependsOn addNativeDependencies // Make sure all native dependencies are specified
doFirst {
def classPath = []
project.ext.commit = System.env.GIT_COMMIT
project.ext.branch = System.env.GIT_BRANCH
try {
def git = Grgit.open(dir: project.projectDir)
project.ext.commit = commit ?: git.head().id
project.ext.branch = branch ?: git.branch.current().name
if (project.version != 'unspecified') {
// Leave version as-is
configurations.runtimeClasspath.each {
if (isDependencyRequested(it.getName())) {
classPath.add("lib/" + it.getName())
} else {
// Resolve version from Git
def tag = version_findRelevantTag(git)
if (tag == null) {
String suffix
if (project.hasProperty('buildId')) {
suffix = project.buildId;
} else {
suffix = java.time.ZonedDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern('yyyy_MM_dd'))
}
project.version = "999.0.0-$suffix"
logger.warn 'Git repository does not contain an applicable tag, using dummy version {}\nSpecify version with -Pversion=1.2.3 or create a Git tag named v1.2.3', project.version
} else {
project.version = version_parseVersion(tag.name, tag.commit != git.head())
}
}
} catch (org.eclipse.jgit.errors.RepositoryNotFoundException e) {
if (project.version == 'unspecified') project.version = 'dev'
project.ext.commit = commit ?: '-'
project.ext.branch = branch ?: '-'
logger.warn 'No Git repository found in project root, using dummy version {}\nSpecify version with -Pversion=1.2.3 or create a Git tag named v1.2.3', project.version
}
if (branch.contains '/') {
// Strip remote - no one wants that
project.ext.branch = branch.takeAfter '/'
}
if (!project.hasProperty('buildId')) {
project.ext.buildId = '-'
println "\tRemoving from JAR classpath (not requested): " + it.getName()
}
}
doLast {
if (classPath.size() == configurations.runtimeClasspath.size()) {
println "Nothing removed from JAR classpath"
}
jar {
manifest {
attributes(
"Main-Class": "ru.windcorp.progressia.client.ProgressiaClientMain",
"Class-Path": configurations.runtimeClasspath.collect { "lib/" + it.getName() } .findAll { isDependencyRequested(it) } .join(' ')
)
}
}
}
}
jar.dependsOn specifyLocalManifest
/*
* Apply LWJGL logic
*/
apply from: 'build_logic/lwjgl.gradle'
/*
* Copy libraries into build/libs/lib directory, next to Progressia.jar
* Library export
*/
task exportLibs(type: Sync) {
description 'Copies runtime libraries into a subdirectory next to the output JAR.'
mustRunAfter addNativeDependencies
jar.dependsOn exportLibs
dependsOn lwjgl_addNativesToRuntimeOnly
// from defined in configureManifest
into 'build/libs/lib'
into libsDirectory.get().getAsFile().getPath() + "/lib"
exclude { !isDependencyRequested(it.getName()) }
from configurations.runtimeClasspath
}
jar.dependsOn(exportLibs)
/*
* Configure JAR manifest
* Packaging
*/
task configureManifest {
description 'Populates JAR manifest with Main-Class, Class-Path and version metadata.'
jar.dependsOn configureManifest
dependsOn resolveVersion
dependsOn lwjgl_addNativesToRuntimeOnly
doFirst {
def classPath = project.lwjgl.replaceNativesIn(configurations.runtimeClasspath)
exportLibs.from classPath
jar.manifest.attributes(
'Main-Class': 'ru.windcorp.progressia.client.ProgressiaClientMain',
'Class-Path': classPath.collect { "lib/${java.net.URLEncoder.encode it.name}" } .join(' '),
'Specification-Title': 'Progressia',
'Implementation-Title': 'Progressia',
'Implementation-Version': project.version,
'Implementation-Version-Git-Commit': project.commit,
'Implementation-Version-Git-Branch': project.branch,
'Implementation-Version-BuildId': project.buildId,
)
}
}
/*
* Packaging working directory configuration
*/
import java.nio.file.*
import java.nio.file.attribute.*
task deletePackagingDirs(type: Delete) {
description 'Deletes build/tmp/packaging directory.'
followSymlinks = false
delete 'build/tmp/packaging'
}
task linkBuildOutputForPackaging {
description 'Symlinks the contents of build/libs into packaging working directory.'
task packageDebian(type: Exec) {
description 'Builds the project and creates a Debain package.'
group 'Progressia'
dependsOn build
mustRunAfter deletePackagingDirs
dependsOn requestLinuxDependencies
onlyIf { preparePackaging.ext.mode == 'symlink' }
ext.from = 'build/libs'
ext.into = "build/tmp/packaging/workingDir/${ -> preparePackaging.ext.buildDest}"
inputs.dir from
outputs.dir into
commandLine './buildPackages.sh', 'debian'
doLast {
def fromPath = Paths.get from
def intoPath = Paths.get into
Files.createDirectories intoPath
Files.list(fromPath).each {
def fileName = it.fileName.toString()
// Exclude all JARs except the current one
if (fileName ==~ "${project.name}.*\\.jar" && fileName != tasks.jar.archiveFileName.get())
return
Files.createSymbolicLink intoPath.resolve(it.fileName), intoPath.relativize(it)
}
println "Debian package available in build_packages/"
}
}
task copyBuildOutputForPackaging(type: Copy) {
description 'Copies the contents of build/libs into packaging working directory.'
task packageWindows(type: Exec) {
description 'Builds the project and creates a Windows installer.'
group 'Progressia'
dependsOn build
mustRunAfter deletePackagingDirs
dependsOn requestWindowsDependencies
onlyIf { preparePackaging.ext.mode == 'copy' }
commandLine './buildPackages.sh', 'windows'
from 'build/libs'
filesMatching("${project.name}*.jar") {
include tasks.jar.archiveFileName.get()
}
into "build/tmp/packaging/workingDir/${ -> preparePackaging.ext.buildDest}"
}
task preparePackaging {
preparePackaging.ext.buildDest = ''
preparePackaging.ext.mode = 'symlink'
dependsOn deletePackagingDirs
dependsOn linkBuildOutputForPackaging
dependsOn copyBuildOutputForPackaging
}
/*
* Apply all packaging scripts
*/
new File(projectDir, 'build_logic/packaging').list().each {
apply from: "build_logic/packaging/$it/script.gradle"
}
/*
* Ensure no more than one packaging task is scheduled
*/
gradle.taskGraph.whenReady { graph ->
if (graph.allTasks.count { it.name ==~ /package[^_]*/ } > 1) {
def offenders = graph.allTasks.findAll { it.name ==~ /package[^_]*/ }
throw new GradleException("Cannot execute multiple package tasks within a single build\n" +
"\tOffending tasks: $offenders")
doLast {
println "Windows installer available in build_packages/"
}
}
/*
* Convenience build tasks
*/
task buildCrossPlatform {
description 'Builds the project including native libraries for all available platforms.'
group 'Progressia'
@ -396,17 +299,17 @@ task buildCrossPlatform {
dependsOn build
doLast {
logger.info 'Native libraries for all platforms have been added'
println "Native libraries for all platforms have been added"
}
}
task buildLocal {
description "Builds the project including only native libraries for current platform (${lwjgl.localArch})."
description "Builds the project including only native libraries for current platform ($lwjglNatives)."
group 'Progressia'
dependsOn build
doLast {
logger.info "Native libraries only for platform ${lwjgl.localArch} have been added"
println "Native libraries only for platform $lwjglNatives have been added"
}
}

191
buildPackages.sh Executable file
View File

@ -0,0 +1,191 @@
#!/bin/bash
#
# Progressia
# Copyright (C) 2020-2021 Wind Corporation and contributors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
echoerr() { echo "$@" 1>&2; }
buildDebianPackage() {
# Commands that must be available to execute this action
requiredCommands='dpkg-deb fakeroot'
# Package name. Sync with control file manually!
name='progressia-techdemo'
# Version that the package will receive. Sync with control file manually!
version='1.0_all'
# This directory will be copied into $tmpDir
templateDirectory="build_packages/DEB/template"
# Files that must be present
requiredFiles="$templateDirectory/DEBIAN/control"
nameAndVersion="$name-$version"
tmpDir="build_packages/DEB/$nameAndVersion"
outputFile="build_packages/DEB/$nameAndVersion.deb"
echo "Checking environment to build Debian package"
for item in $requiredCommands; do
if command -v "$item" &> /dev/null; then
echo "- $item found"
else
echoerr "Command $item not found, cannot package"
exit 100
fi
done
for file in $requiredFiles; do
if ! [ -r "$file" ]; then
echoerr "$file is missing or not readable, cannot package"
exit 101
else
echo "- $file is present and readable"
fi
done
echo "Environment OK; packaging Debian package"
exitCode=0
{
shareDir="$tmpDir/usr/share/progressia"
mkdir -p "$tmpDir" &&
mkdir -p "$shareDir" &&
cp -r "$templateDirectory"/* "$tmpDir" &&
cp -r 'build/libs/lib' "$shareDir/lib" &&
cp 'build/libs/Progressia.jar' "$shareDir/Progressia.jar" &&
echo "------ DPKG-DEB ------" &&
fakeroot dpkg-deb --build "$tmpDir" &&
echo "---- DPKG-DEB END ----" &&
mv "$outputFile" build_packages
} || {
echoerr "Could not create Debian package"
exitCode=1
}
{
if [ -d "$tmpDir" ]; then
rm -r "$tmpDir"
fi
echo "Cleaned up"
} || {
echoerr "Could not clean up after packaging Debian package"
exitCode=2
}
exit "$exitCode"
}
buildWindowsInstaller() {
# Commands that must be available to execute this action
requiredCommands='makensis'
# NSIS configuration file that must be present
configurationFile='build_packages/NSIS/ProgressiaInstaller.nsi'
# File that will be output
outputFile='build_packages/NSIS/ProgressiaInstaller.exe'
echo "Checking environment to build Windows installer"
for item in $requiredCommands; do
if command -v "$item" &> /dev/null; then
echo "- $item found"
else
echoerr "Command $item not found, cannot build"
exit 100
fi
done
if ! [ -r "$configurationFile" ]; then
echoerr "$configurationFile is missing or not readable, cannot build"
exit 101
else
echo "- $configurationFile is present and readable"
fi
echo "Environment OK; building Windows installer"
exitCode=0
{
cp -r 'build/libs/lib' 'build_packages/NSIS/lib' &&
cp 'build/libs/Progressia.jar' 'build_packages/NSIS/Progressia.jar' &&
cp 'LICENSE' 'build_packages/NSIS/LICENSE.txt' &&
echo "------ NSIS ------" &&
makensis "$configurationFile" &&
echo "---- NSIS END ----" &&
mv "$outputFile" build_packages
} || {
echoerr "Could not build Windows installer"
exitCode=1
}
{
if [ -d 'build_packages/NSIS/lib' ]; then
rm -r 'build_packages/NSIS/lib'
fi
if [ -e 'build_packages/NSIS/Progressia.jar' ]; then
rm 'build_packages/NSIS/Progressia.jar'
fi
if [ -e 'build_packages/NSIS/LICENSE.txt' ]; then
rm 'build_packages/NSIS/LICENSE.txt'
fi
echo "Cleaned up"
} || {
echoerr "Could not clean up after building Windows installer"
exitCode=2
}
exit "$exitCode"
}
printUsage() {
echoerr "Usage: $0 TARGET"
echoerr " where TARGET is 'debian' or 'windows'"
}
if [ -n "$2" ]; then
echoerr "Too many arguments."
printUsage
exit 202
fi
case "$1" in
"debian")
buildDebianPackage
;;
"windows")
buildWindowsInstaller
;;
"")
echoerr "No action specified"
printUsage
exit 200
;;
"--help" | "-help" | "help" | "?")
printUsage
;;
*)
echoerr "Unknown action '$1'"
printUsage
exit 201
;;
esac

View File

@ -1,149 +0,0 @@
/*
* Build logic for Progressia
* LWJGL dependency logic
*/
project.ext.lwjgl = new HashMap<>()
// Version of LWJGL
lwjgl.version = '3.3.0'
/*
* Target platforms for current operation.
* This is filled in by the request* tasks. This is referenced by the addLwjglNatives task.
* When empty, current platform is assumed.
*/
lwjgl.targets = new HashSet<String>()
// LWJGL components. To include org.lwjgl:lwjgl-foobar, add 'foobar' to this list.
lwjgl.libraries = [
'opengl',
'glfw',
'openal',
'stb'
]
// Determine the architecture of the build environment
import org.gradle.internal.os.OperatingSystem
switch (OperatingSystem.current()) {
case OperatingSystem.LINUX:
def osArch = System.getProperty('os.arch')
lwjgl.localArch = osArch.startsWith('arm') || osArch.startsWith('aarch64')
? "linux-${osArch.contains('64') || osArch.startsWith('armv8') ? 'arm64' : 'arm32'}"
: 'linux'
break
case OperatingSystem.MAC_OS:
lwjgl.localArch = System.getProperty('os.arch').startsWith('aarch64') ? 'macos-arm64' : 'macos'
break
case OperatingSystem.WINDOWS:
def osArch = System.getProperty('os.arch')
lwjgl.localArch = osArch.contains('64')
? "windows${osArch.startsWith('aarch64') ? '-arm64' : ''}"
: 'windows-x86'
break
default:
logger.info "Unknown or unsupported OS type according to Gradle's org.gradle.internal.os.OperatingSystem: ${OperatingSystem.current()}"
break
}
configurations {
create 'lwjglNatives'
}
// Declare pure-Java dependencies
dependencies {
// BOM
def bom = platform("org.lwjgl:lwjgl-bom:${lwjgl.version}")
implementation bom
lwjglNatives bom
// Core
implementation 'org.lwjgl:lwjgl'
// Local natives for core
runtimeOnly "org.lwjgl:lwjgl::natives-${lwjgl.localArch}"
// Components
lwjgl.libraries.each { lib ->
implementation "org.lwjgl:lwjgl-$lib"
// Local natives for component
runtimeOnly "org.lwjgl:lwjgl-$lib::natives-${lwjgl.localArch}"
}
}
/*
* Adds LWJGL native libraries to lwjglNatives configuration
*/
task lwjgl_addNativesToRuntimeOnly {
doFirst {
if (project.hasProperty('forceTargets')) {
try {
def oldTargets = lwjgl.targets.join(',')
lwjgl.targets.clear()
lwjgl.targets.addAll project.forceTargets.split(',')*.trim().collect { it == 'local' ? lwjgl.localArch : it }
logger.info 'Overriding selected platforms {} with {}', oldTargets, lwjgl.targets.join(',')
} catch (Exception e) {
throw new GradleException("Could not parse forceTargets \"${project.forceTargets}\", expecting platform-1,platform-2,local", e)
}
}
if (lwjgl.targets.isEmpty()) {
logger.info 'Adding LWJGL native dependencies for local platform only: {}', lwjgl.localArch
lwjgl.targets.add lwjgl.localArch
} else {
logger.info 'Adding LWJGL native dependencies for platforms: {}', lwjgl.targets.sort().join(', ')
}
if (lwjgl.targets.contains(null)) {
if (lwjgl.localArch != null) {
throw new GradleException("Requested local LWJGL natives; could not determine local architecture for OS ${OperatingSystem.current()} with os.arch ${System.getProperty('os.arch')}")
} else {
throw new GradleException("LWJGL targets resolved to ${lwjgl.targets}")
}
}
dependencies {
lwjgl.targets.each { target ->
lwjglNatives "org.lwjgl:lwjgl::natives-$target"
lwjgl.libraries.each { lib ->
lwjglNatives "org.lwjgl:lwjgl-$lib::natives-$target"
}
}
}
}
}
// Replaces LWJGL natives in the given configuration with the requested ones
lwjgl.replaceNativesIn = { config ->
new ArrayList<File>().tap {
addAll config
removeIf { it.name ==~ /.*lwjgl.*natives.*/ }
addAll project.configurations.lwjglNatives
}
}
task requestCrossPlatformDependencies {
description 'Adds LWJGL natives for all available platforms.'
lwjgl_addNativesToRuntimeOnly.mustRunAfter requestCrossPlatformDependencies
}
def requestTask(String name, String... targets) {
def theTask = task "request${name}Dependencies"
theTask.doFirst {
lwjgl.targets.addAll targets
}
theTask.description "Adds LWJGL natives for $name (${targets.join(', ')})."
requestCrossPlatformDependencies.dependsOn theTask
lwjgl_addNativesToRuntimeOnly.mustRunAfter theTask
}
requestTask 'Linux', 'linux', 'linux-arm32', 'linux-arm64'
requestTask 'Windows', 'windows', 'windows-arm64', 'windows-x86'
requestTask 'MacOS', 'macos', 'macos-arm64'

View File

@ -1,42 +0,0 @@
task packageDeb_processResources(type: Copy) {
dependsOn resolveVersion
dependsOn preparePackaging
from 'src/packaging/deb'
filesMatching('DEBIAN/control') {
expand(version: { -> project.version})
}
into 'build/tmp/packaging/workingDir'
}
task packageDeb_configure() {
preparePackaging.mustRunAfter packageDeb_configure
doLast {
tasks.preparePackaging.ext.buildDest = 'usr/share/progressia'
tasks.preparePackaging.ext.mode = 'copy'
}
}
task packageDeb(type: Exec) {
description 'Builds the project and creates a Debian package.'
group 'Progressia'
dependsOn packageDeb_configure
dependsOn requestLinuxDependencies
dependsOn build
dependsOn preparePackaging
dependsOn packageDeb_processResources
doFirst {
mkdir 'build/packages'
}
executable 'dpkg-deb'
args '--root-owner-group'
args '--build', 'build/tmp/packaging/workingDir'
args 'build/packages'
}

View File

@ -1,54 +0,0 @@
task packageNsis_processResources(type: Copy) {
dependsOn preparePackaging
from ('src/packaging/nsis') {
exclude 'left_side.png'
}
from('LICENSE') {
rename 'LICENSE', 'LICENSE.txt'
}
into 'build/tmp/packaging/workingDir'
}
task packageNsis_generateIcon(type: Exec) {
mustRunAfter preparePackaging
executable 'convert'
args files('src/main/resources/assets/icons/*.original.png').files*.path
args 'build/tmp/packaging/workingDir/logo.ico'
}
task packageNsis_generateLeftSide(type: Exec) {
mustRunAfter preparePackaging
executable 'convert'
args 'src/packaging/nsis/left_side.png'
args '-alpha', 'off'
args 'BMP3:build/tmp/packaging/workingDir/left_side.bmp'
}
task packageNsis(type: Exec) {
description 'Builds the project and creates a Windows NSIS installer.'
group 'Progressia'
dependsOn requestWindowsDependencies
dependsOn build
dependsOn resolveVersion
dependsOn preparePackaging
dependsOn packageNsis_processResources
dependsOn packageNsis_generateIcon
dependsOn packageNsis_generateLeftSide
doFirst {
mkdir 'build/packages'
}
executable 'makensis'
args '-NOCONFIG'
args "-DPROJECT_NAME=${project.name}"
args "-DPROJECT_VERSION=${ -> project.version}"
args "-DMAIN_JAR_FILE=${ -> project.tasks.jar.archiveFileName.get()}"
args "-DOUTPUT_DIR=${project.buildDir.absolutePath}/packages"
args 'build/tmp/packaging/workingDir/config.nsi'
}

View File

@ -1,45 +0,0 @@
task packageZip_processResources(type: Copy) {
dependsOn preparePackaging
from ('src/packaging/zip') {
filesMatching('start.*') {
filter(
org.apache.tools.ant.filters.ReplaceTokens,
tokens: [mainJarFile: project.tasks.jar.archiveFileName.get()]
)
}
}
from ('src/main/resource/assets/icons/logo256.original.png') {
rename 'logo256.original.png', 'logo.png'
}
from('LICENSE') {
rename 'LICENSE', 'LICENSE.txt'
}
into 'build/tmp/packaging/workingDir'
}
task packageZip(type: Zip) {
description 'Builds the project and creates a cross-platform ZIP package.'
group 'Progressia'
dependsOn resolveVersion
dependsOn requestCrossPlatformDependencies
dependsOn build
dependsOn preparePackaging
dependsOn packageZip_processResources
archiveBaseName = project.name
archiveAppendix = 'universal'
doFirst {
archiveVersion = project.version
}
doFirst {
mkdir 'build/packages'
}
from 'build/tmp/packaging/workingDir'
destinationDirectory = file('build/packages')
}

View File

@ -1,8 +1,8 @@
Package: progressia
Version: ${version}
Package: progressia-techdemo
Version: 1.0
Section: custom
Priority: optional
Architecture: all
Maintainer: Javapony <kvadropups@gmail.com>
Depends: java8-runtime
Description: Progressia - a 3D sandbox survival game
Description: Progressia Techdemo release

View File

@ -10,10 +10,7 @@
;--------------------------------
;General
; Expecting the following symbols from caller:
; PROJECT_NAME
; PROJECT_VERSION
; MAIN_JAR_FILE
!define PROJECT_NAME "Progressia"
; MUI Settings / Icons
!define MUI_ICON "logo.ico"
@ -31,7 +28,7 @@
;Name and file
Name "${PROJECT_NAME}"
OutFile "${OUTPUT_DIR}/${PROJECT_NAME}-${PROJECT_VERSION}-installer.exe"
OutFile "${PROJECT_NAME}Installer.exe"
Unicode True
;Default installation folder
@ -82,12 +79,12 @@ Section "Install ${PROJECT_NAME}" SEC0000
SetOverwrite on
;Files
File "${MAIN_JAR_FILE}"
File Progressia.jar
File logo.ico
File /r lib
;Store installation folder
WriteRegStr HKLM "SOFTWARE\${PROJECT_NAME}" "Install_Dir" "$INSTDIR"
WriteRegStr HKLM SOFTWARE\Progressia "Install_Dir" "$INSTDIR"
;Create uninstaller
@ -99,14 +96,14 @@ SectionEnd
Section "Create Desktop Shortcut" SEC0001
SetOutPath "$APPDATA\${PROJECT_NAME}"
CreateShortCut "$DESKTOP\${PROJECT_NAME}.lnk" "$INSTDIR\${MAIN_JAR_FILE}" "" "$INSTDIR\logo.ico"
CreateShortCut "$DESKTOP\${PROJECT_NAME}.lnk" "$INSTDIR\${PROJECT_NAME}.jar" "" "$INSTDIR\logo.ico"
SectionEnd
Section "Start Menu Shortcuts" SEC0002
CreateDirectory "$SMPROGRAMS\${PROJECT_NAME}"
CreateShortcut "$SMPROGRAMS\${PROJECT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
CreateShortcut "$SMPROGRAMS\${PROJECT_NAME}\${PROJECT_NAME}.lnk" "$INSTDIR\${MAIN_JAR_FILE}" "" "$INSTDIR\logo.ico"
CreateShortcut "$SMPROGRAMS\${PROJECT_NAME}\${PROJECT_NAME}.lnk" "$INSTDIR\${PROJECT_NAME}.jar" "" "$INSTDIR\logo.ico"
SectionEnd
@ -118,7 +115,7 @@ Section "Uninstall"
;ADD YOUR OWN FILES HERE...
Delete $INSTDIR\Uninstall.exe
Delete "$INSTDIR\${MAIN_JAR_FILE}"
Delete $INSTDIR\Progressia.jar
Delete $INSTDIR\lib\*.*
Delete $INSTDIR\logo.ico
@ -149,7 +146,7 @@ SectionEnd
Function LaunchLink
SetOutPath "$APPDATA\${PROJECT_NAME}"
ExecShell "" "$INSTDIR\${MAIN_JAR_FILE}"
ExecShell "" "$INSTDIR\${PROJECT_NAME}.jar"
FunctionEnd
;--------------------------------

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

View File

@ -1,12 +0,0 @@
# Progressia Region File
## Description
The `.progressia_region` file type is used for all region files in the game Progressia. Each region file contains a cube of 16x16x16 chunks.
## Header
The header of the file is 16&nbsp;400 bytes. Every file starts with the string byte sequence `\x50\x52\x4F\x47` (UTF-8 for `PROG`), followed with the three integer values of the region position, in region coordinates. After this, there is exactly 16KiB of space in the header, which stores the offsets to the chunks' data. This space holds an integer, 4 bytes, for each chunk in the region. The integer value starts at 0 for every chunk, and is changed to the location of the chunk data once created. These are indexed in order by flattening the 3D in-chunk coordinates into a number between 0 and 4095 according to the formula `offset = 256*x+ 16*y + z` for chunk at (x, y, z). To convert from this offset value to the offset in bytes, use `byte_offset = 16400 + 64*n`.
## Sectors
Sectors are what is used to store chunk data, and are not linear, but are followed until they reach an ending block. Each is 64 bytes, which is used in the header section to find the byte offset. Each sector starts with a identification byte, followed by the sector data.
0. Ending - This sector is empty, and marks the end of the chunk data (This may change in the future.
1. Data - This sector contains chunk data for a single chunk. The second byte of this sector contains a counter byte, which is a form of "checksum" to make sure that the program is reading the proper sectors in order. This starts at 0 for the first data sector and increments by one for each new data sector.
2. Partition Link - This sector only contains another offset value, which is where the next sector is. This allows for infinite chunk size, avoiding "chunk dupes" as were present in Minecraft without reverting any chunks.
3. Bulk Data - These would be used for many chunks in the same region that contain exactly the same data, e.g. all solid chunks underground. Exists so the program knows not to overwrite them, and just make new chunk data if modified. Not yet implemented.

View File

@ -1,10 +1,8 @@
# Build Guide
This document is a guide to building Progressia from source. For quick reference, see
[Build Script Reference](BuildScriptReference.md).
This document is a guide to building Progressia from source.
Compilation should be possible on all platforms that support JDK 8 or later, however, packaging scripts require
additional programs in `PATH`.
Compilation should be possible on all platforms that support JDK 8 or later, however, packaging scripts require Bash.
This guide assumes you are familiar with using a terminal or Windows Command Prompt or PowerShell.
@ -143,8 +141,8 @@ build.
Some users might find the need to build for a specific set of platforms. Inclusion of GNU/Linux, Windows or MacOS
dependencies individually can be controlled with the following arguments to the `./gradlew build` command:
- `requestLinuxDependencies` requests that `natives-linux`, `natives-linux-arm32` and `natives-linux-arm64` binaries are included;
- `requestWindowsDependencies` requests that `natives-windows`, `natives-windows-arm64` and `natives-windows-x86` binaries are included;
- `requestMacOSDependencies` requests that `natives-macos`, `natives-macos-arm64` binaries are included.
- `requestWindowsDependencies` requests that `natives-windows` and `natives-windows-x86` binaries are included;
- `requestMacOSDependencies` requests that `natives-macos` binaries are included.
These requests can be applied in any combination. For example, the following command produces a build containing only
GNU/Linux and Windows natives:
@ -152,46 +150,54 @@ GNU/Linux and Windows natives:
./gradlew build requestLinuxDependencies requestWindowsDependencies
```
For finer control please edit `build.gradle` manually by adding the desired natives to the `project.ext.platforms` set like so:
```
project.ext.platforms = new HashSet<>()
project.ext.platforms.add 'natives-windows-x86'
```
## Packaging
A universal ZIP distribution, a Debian package and a Windows NSIS installer may be created automatically by the build
script.
### Creating a universal ZIP package
A universal cross-platform ZIP archive can be created with the following Gradle task:
```
./gradlew packageZip
```
Gradle will then build all artifacts necessary to run the game on all available platforms and package game files,
libraries, launch scripts, etc. into a compressed ZIP archive.
The resulting file can be found in `build/packages/`
A Debian package and a Windows installer can be created automatically on systems that support Bash. These tasks are delegated
by Gradle to `buildPackages.sh` in repository root. This script checks the environment and assembles the requested output; the
resulting files are moved into `build_packages`.
### Creating a Debian package
A Debian package can be created with the following Gradle task:
```
./gradlew packageDeb
./gradlew packageDebian
```
Gradle will then build all artifacts necessary to run the game on GNU/Linux (all three architectures) and invoke
`dpkg-deb`. Commands `dpkg-deb` must be available in system path in order to build the package.
`./buildPackages.sh debian`. Commands `dpkg-deb` and `fakeroot` must be available in system path in order to build the package.
### Creating a Windows installer
A Windows NSIS installer can be created with the following Gradle task:
A Windows installer can be created with the following Gradle task:
```
./gradlew packageNsis
./gradlew packageWindows
```
Gradle will then build all artifacts necessary to run the game on Windows (both x64 and x86 architectures) and invoke
`makensis`.
`./buildPackages.sh windows`.
Windows installers are implemented with [NSIS](https://nsis.sourceforge.io/). [ImageMagick](https://imagemagick.org),
a command-line image editing tool, is used to generate some assets for the installer. Commands `makensis` and
`convert` (from ImageMagick) must be available in system path in order to build the installer.
Windows installers are implemented with [NSIS](https://nsis.sourceforge.io/). Command `makensis` must be available in system
path in order to build the installer.
## Gradle tasks summary
- `buildLocal` creates a build optimized for current platform. Use this to quickly build the game during development.
- `buildCrossPlatform` creates a build that supports all known architectures. Use this to build a universal version of the game.
- `build` currently a synonym of `buildLocal`; creates a default build.
- `packageDebian` creates a Debian package. Do not invoke together with `packageWindows`.
- `packageWindows` creates a Windows installer. Do not invoke together with `packageDebian`.
- `requestLinuxDependencies` requests that `natives-linux`, `natives-linux-arm32` and `natives-linux-arm64` binaries are included when building.
- `requestWindowsDependencies` requests that `natives-windows` and `natives-windows-x86` binaries are included when building.
- `requestMacOSDependencies` requests that `natives-macos` binaries are included when building.
- `requestCrossPlatformDependencies` requests that all binaries are included when building.
All other basic and Java-related Gradle tasks are available as well.

View File

@ -1,112 +0,0 @@
# Build Script Reference
This document is a user's reference for the build script of Progressia. For a beginner-friendly guide, see
[Build Guide](BuildGuide.md).
## Gradle tasks summary
- `buildLocal` creates a build optimized for current platform. Use this to quickly build the game during development.
- `buildCrossPlatform` creates a build that supports all known architectures. Use this to build a universal version of the game.
- `build` currently a synonym of `buildLocal`; creates a default build.
- `packageZip` creates a universal ZIP. Incompatible with other `package` tasks.
- `packageDeb` creates a Debian package. Incompatible with other `package` tasks.
- `packageNsis` creates a Windows NSIS installer. Incompatible with other `package` tasks.
- `requestLinuxDependencies` requests that `natives-linux`, `natives-linux-arm32` and `natives-linux-arm64` binaries are included when building.
- `requestWindowsDependencies` requests that `natives-windows`, `natives-windows-arm64` and `natives-windows-x86` binaries are included when building.
- `requestMacOSDependencies` requests that `natives-macos` and `natives-macos-arm64` binaries are included when building.
- `requestCrossPlatformDependencies` requests that all binaries are included when building.
To execute a task, run `./gradlew <task-name>`.
`build`-type tasks output the executable JAR and all libraries required at runtime into `build/libs`. `package`-type
tasks output packages into `build/packages`.
## Packaging tasks
Some packaging tasks require additional software in `PATH`.
| Task | Commands required in `PATH` |
|---------------|------------------------------------------|
| `packageDeb` | `dpkg-deb` |
| `packageZip` | _none_ |
| `packageNsis` | `makensis`, `convert` (from ImageMagick) |
## Version and metadata
### Version scheme
Progressia builds are identified by four parameters: version, Git commit, Git branch and build ID.
Versions roughly follow [semantic versioning](https://semver.org/spec/v2.0.0.html), with each version fitting the
`MAJOR.MINOR.PATCH[-SUFFIX]` pattern. Depending on the build environment (see below), version is either "real" with
no metadata (e.g. `0.43.2` or `1.2.1-beta`) or a dummy fallback with build metadata (e.g. `999.0.0-2021_07_23` or
`999.0.0-WJ3`).
### Version detection
Build script considers three scenarios when determining the version:
1. `version` project property is set explicitly. This may be done in a variety of ways, for example with command line
argument `-Pversion=1.2.3`
(see [Gradle docs](https://docs.gradle.org/current/userguide/build_environment.html#sec:project_properties))
2. Local Git repository is found, and HEAD is tagged appropriately: version is the tag name with leading `v`
stripped. Example: `v1.2.3` is version `1.2.3`
3. Local Git repository is found, and some ancestor of HEAD is tagged appropriately: version is the tag name with
leading `v` stripped and PATCH incremented by one. Example: `v1.2.3` is version `1.2.4`
Tags not named like `vMAJOR.MINOR.PATCH[-SUFFIX]` are ignored for cases 2 and 3.
In all other cases, a fallback dummy value is used for version, appended with build ID or current date.
### Git metadata
Git commit is determined from `GIT_COMMIT` environment variable if it exists, or the state of the local Git
repository, if any, or `-`.
Git branch is determined from `GIT_BRANCH` environment variable if it exists, or the state of the local Git
repository, if any, or `-`.
The names of the environment variables are picked to assist Jenkins builds.
### Build ID
Build ID uniquely identifies artifacts produced by automated build systems. Build ID must be provided explicitly; it
is `-` unless specified otherwise.
The proposed scheme for naming build IDs is `<builder><build-system><build attempt no.>`. For example, builds
executed by WindCorp Jenkins suite have build IDs like `WJ3` or `WJ142`.
Build ID may be set with `buildId` project property. This may be done in a variety of ways, for example with command
line argument `-PbuildId=WJ3`
(see [Gradle docs](https://docs.gradle.org/current/userguide/build_environment.html#sec:project_properties)).
## Native libraries
LWJGL uses native libraries. Build script declares platform-specific dependencies based on the set of target
platforms, `project.ext.lwjgl.targets` (aka `lwjgl.targets`). These dependencies are added to `runtimeOnly`
configuration.
When this set is empty, the script selects natives for current platform. Otherwise, all platforms in the set are
included.
`lwjgl.targets` is populated automatically by packaging tasks and by `buildCrossPlatform`. To add extra targets,
``requestXxxDependencies` tasks may be used.
Target selection mechanism may be overridden with `forceTargets` project property. This may be done in a variety of
ways, for example with command line argument `-PforceTargets=windows-x86,local`
(see [Gradle docs](https://docs.gradle.org/current/userguide/build_environment.html#sec:project_properties)). The
value is a comma-separated list of target architectures. `local` target will be replaced with the automatically
detected current architecture.
### Available targets
| Name | Task |
|-----------------|------------------------------|
| `linux` | `requestLinuxDependencies` |
| `linux-arm32` | `requestLinuxDependencies` |
| `linux-arm64` | `requestLinuxDependencies` |
| `windows` | `requestWindowsDependencies` |
| `windows-arm64` | `requestWindowsDependencies` |
| `windows-x86` | `requestWindowsDependencies` |
| `macos` | `requestMacOSDependencies` |
| `macos-arm64` | `requestMacOSDependencies` |

View File

@ -42,16 +42,3 @@ Run configurations are used by Intellij IDEA to specify how a project must be ru
9. Click 'Apply' to save changes.
Step 8 is required to specify that the game must run in some directory other than the project root, which is the default in Intellij IDEA.
### Applying formatting templates
Windcorp's Progressia repository is formatted with a style defined for Eclipse IDE (sic) in
`templates_and_presets/eclipse_ide`.
Please apply these templates to the project to automatically format the source in a similar fashion.
1. In project context menu, click 'File->Properties'. (`Ctrl+Alt+S`)
2. In 'Editor' > 'Code Style' > 'Java', press gear icon, then click 'Import Scheme' > 'Eclipse code style'
3. In Scheme select 'Project'
4. Open the file `templates_and_presets/eclipse_ide/FormatterProfile.xml` in 'Select Path'.
5. Inside 'Import Scheme' widow click 'Current Scheme' check box after press OK

Binary file not shown.

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

259
gradlew vendored
View File

@ -1,7 +1,7 @@
#!/bin/sh
#!/usr/bin/env sh
#
# Copyright © 2015-2021 the original authors.
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -17,113 +17,78 @@
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
MAX_FD="maximum"
warn () {
echo "$*"
} >&2
}
die () {
echo
echo "$*"
echo
exit 1
} >&2
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD=$JAVA_HOME/bin/java
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -132,7 +97,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@ -140,95 +105,79 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

25
gradlew.bat vendored
View File

@ -29,9 +29,6 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@ -40,7 +37,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -54,7 +51,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -64,14 +61,28 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell

View File

@ -45,7 +45,7 @@ public class OpenSimplex2S {
source[i] = i;
for (int i = PSIZE - 1; i >= 0; i--) {
seed = seed * 6364136223846793005L + 1442695040888963407L;
int r = (int)((seed + 31) % (i + 1));
int r = (int) ((seed + 31) % (i + 1));
if (r < 0)
r += (i + 1);
perm[i] = source[r];
@ -72,9 +72,9 @@ public class OpenSimplex2S {
}
/**
* 2D SuperSimplex noise, with Y pointing down the main diagonal.
* Might be better for a 2D sandbox style game, where Y is vertical.
* Probably slightly less optimal for heightmaps or continent maps.
* 2D SuperSimplex noise, with Y pointing down the main diagonal. Might be
* better for a 2D sandbox style game, where Y is vertical. Probably
* slightly less optimal for heightmaps or continent maps.
*/
public double noise2_XBeforeY(double x, double y) {
@ -86,8 +86,8 @@ public class OpenSimplex2S {
}
/**
* 2D SuperSimplex noise base.
* Lookup table implementation inspired by DigitalShadow.
* 2D SuperSimplex noise base. Lookup table implementation inspired by
* DigitalShadow.
*/
private double noise2_Base(double xs, double ys) {
double value = 0;
@ -97,11 +97,8 @@ public class OpenSimplex2S {
double xsi = xs - xsb, ysi = ys - ysb;
// Index to point list
int a = (int)(xsi + ysi);
int index =
(a << 2) |
(int)(xsi - ysi / 2 + 1 - a / 2.0) << 3 |
(int)(ysi - xsi / 2 + 1 - a / 2.0) << 4;
int a = (int) (xsi + ysi);
int index = (a << 2) | (int) (xsi - ysi / 2 + 1 - a / 2.0) << 3 | (int) (ysi - xsi / 2 + 1 - a / 2.0) << 4;
double ssi = (xsi + ysi) * -0.211324865405187;
double xi = xsi + ssi, yi = ysi + ssi;
@ -112,7 +109,8 @@ public class OpenSimplex2S {
double dx = xi + c.dx, dy = yi + c.dy;
double attn = 2.0 / 3.0 - dx * dx - dy * dy;
if (attn <= 0) continue;
if (attn <= 0)
continue;
int pxm = (xsb + c.xsv) & PMASK, pym = (ysb + c.ysv) & PMASK;
Grad2 grad = permGrad2[perm[pxm] ^ pym];
@ -126,15 +124,16 @@ public class OpenSimplex2S {
}
/**
* 3D Re-oriented 8-point BCC noise, classic orientation
* Proper substitute for what 3D SuperSimplex would be,
* in light of Forbidden Formulae.
* Use noise3_XYBeforeZ or noise3_XZBeforeY instead, wherever appropriate.
* 3D Re-oriented 8-point BCC noise, classic orientation Proper substitute
* for what 3D SuperSimplex would be, in light of Forbidden Formulae. Use
* noise3_XYBeforeZ or noise3_XZBeforeY instead, wherever appropriate.
*/
public double noise3_Classic(double x, double y, double z) {
// Re-orient the cubic lattices via rotation, to produce the expected look on cardinal planar slices.
// If texturing objects that don't tend to have cardinal plane faces, you could even remove this.
// Re-orient the cubic lattices via rotation, to produce the expected
// look on cardinal planar slices.
// If texturing objects that don't tend to have cardinal plane faces,
// you could even remove this.
// Orthonormal rotation. Not a skew transform.
double r = (2.0 / 3.0) * (x + y + z);
double xr = r - x, yr = r - y, zr = r - z;
@ -145,15 +144,17 @@ public class OpenSimplex2S {
/**
* 3D Re-oriented 8-point BCC noise, with better visual isotropy in (X, Y).
* Recommended for 3D terrain and time-varied animations.
* The Z coordinate should always be the "different" coordinate in your use case.
* If Y is vertical in world coordinates, call noise3_XYBeforeZ(x, z, Y) or use noise3_XZBeforeY.
* If Z is vertical in world coordinates, call noise3_XYBeforeZ(x, y, Z).
* For a time varied animation, call noise3_XYBeforeZ(x, y, T).
* Recommended for 3D terrain and time-varied animations. The Z coordinate
* should always be the "different" coordinate in your use case. If Y is
* vertical in world coordinates, call noise3_XYBeforeZ(x, z, Y) or use
* noise3_XZBeforeY. If Z is vertical in world coordinates, call
* noise3_XYBeforeZ(x, y, Z). For a time varied animation, call
* noise3_XYBeforeZ(x, y, T).
*/
public double noise3_XYBeforeZ(double x, double y, double z) {
// Re-orient the cubic lattices without skewing, to make X and Y triangular like 2D.
// Re-orient the cubic lattices without skewing, to make X and Y
// triangular like 2D.
// Orthonormal rotation. Not a skew transform.
double xy = x + y;
double s2 = xy * -0.211324865405187;
@ -167,20 +168,23 @@ public class OpenSimplex2S {
/**
* 3D Re-oriented 8-point BCC noise, with better visual isotropy in (X, Z).
* Recommended for 3D terrain and time-varied animations.
* The Y coordinate should always be the "different" coordinate in your use case.
* If Y is vertical in world coordinates, call noise3_XZBeforeY(x, Y, z).
* If Z is vertical in world coordinates, call noise3_XZBeforeY(x, Z, y) or use noise3_XYBeforeZ.
* For a time varied animation, call noise3_XZBeforeY(x, T, y) or use noise3_XYBeforeZ.
* Recommended for 3D terrain and time-varied animations. The Y coordinate
* should always be the "different" coordinate in your use case. If Y is
* vertical in world coordinates, call noise3_XZBeforeY(x, Y, z). If Z is
* vertical in world coordinates, call noise3_XZBeforeY(x, Z, y) or use
* noise3_XYBeforeZ. For a time varied animation, call noise3_XZBeforeY(x,
* T, y) or use noise3_XYBeforeZ.
*/
public double noise3_XZBeforeY(double x, double y, double z) {
// Re-orient the cubic lattices without skewing, to make X and Z triangular like 2D.
// Re-orient the cubic lattices without skewing, to make X and Z
// triangular like 2D.
// Orthonormal rotation. Not a skew transform.
double xz = x + z;
double s2 = xz * -0.211324865405187;
double yy = y * 0.577350269189626;
double xr = x + s2 - yy; double zr = z + s2 - yy;
double xr = x + s2 - yy;
double zr = z + s2 - yy;
double yr = xz * 0.577350269189626 + yy;
// Evaluate both lattices to form a BCC lattice.
@ -188,10 +192,10 @@ public class OpenSimplex2S {
}
/**
* Generate overlapping cubic lattices for 3D Re-oriented BCC noise.
* Lookup table implementation inspired by DigitalShadow.
* It was actually faster to narrow down the points in the loop itself,
* than to build up the index with enough info to isolate 8 points.
* Generate overlapping cubic lattices for 3D Re-oriented BCC noise. Lookup
* table implementation inspired by DigitalShadow. It was actually faster to
* narrow down the points in the loop itself, than to build up the index
* with enough info to isolate 8 points.
*/
private double noise3_BCC(double xr, double yr, double zr) {
@ -199,9 +203,11 @@ public class OpenSimplex2S {
int xrb = fastFloor(xr), yrb = fastFloor(yr), zrb = fastFloor(zr);
double xri = xr - xrb, yri = yr - yrb, zri = zr - zrb;
// Identify which octant of the cube we're in. This determines which cell
// in the other cubic lattice we're in, and also narrows down one point on each.
int xht = (int)(xri + 0.5), yht = (int)(yri + 0.5), zht = (int)(zri + 0.5);
// Identify which octant of the cube we're in. This determines which
// cell
// in the other cubic lattice we're in, and also narrows down one point
// on each.
int xht = (int) (xri + 0.5), yht = (int) (yri + 0.5), zht = (int) (zri + 0.5);
int index = (xht << 0) | (yht << 1) | (zht << 2);
// Point contributions
@ -230,9 +236,9 @@ public class OpenSimplex2S {
*/
/**
* Generate the 2D noise over a large area.
* Propagates by flood-fill instead of iterating over a range.
* Results may occasionally slightly exceed [-1, 1] due to the grid-snapped pre-generated kernel.
* Generate the 2D noise over a large area. Propagates by flood-fill instead
* of iterating over a range. Results may occasionally slightly exceed [-1,
* 1] due to the grid-snapped pre-generated kernel.
*/
public void generate2(GenerateContext2D context, double[][] buffer, int x0, int y0) {
int height = buffer.length;
@ -241,11 +247,12 @@ public class OpenSimplex2S {
}
/**
* Generate the 2D noise over a large area.
* Propagates by flood-fill instead of iterating over a range.
* Results may occasionally slightly exceed [-1, 1] due to the grid-snapped pre-generated kernel.
* Generate the 2D noise over a large area. Propagates by flood-fill instead
* of iterating over a range. Results may occasionally slightly exceed [-1,
* 1] due to the grid-snapped pre-generated kernel.
*/
public void generate2(GenerateContext2D context, double[][] buffer, int x0, int y0, int width, int height, int skipX, int skipY) {
public void generate2(GenerateContext2D context, double[][] buffer, int x0, int y0, int width, int height,
int skipX, int skipY) {
Queue<AreaGenLatticePoint2D> queue = new LinkedList<AreaGenLatticePoint2D>();
Set<AreaGenLatticePoint2D> seen = new HashSet<AreaGenLatticePoint2D>();
@ -260,16 +267,19 @@ public class OpenSimplex2S {
// - Much faster than computing the kernel equation every time.
// You can remove these lines if you find it's the opposite for you.
// You'll have to double the bounds again in GenerateContext2D
kernel = new double[scaledRadiusY * 2][/*scaledRadiusX * 2*/];
kernel = new double[scaledRadiusY * 2][/* scaledRadiusX * 2 */];
for (int yy = 0; yy < scaledRadiusY; yy++) {
kernel[2 * scaledRadiusY - yy - 1] = kernel[yy] = (double[]) context.kernel[yy].clone();
}
// Get started with one point/vertex.
// For some lattices, you might need to try a handful of points in the cell,
// or flip a couple of coordinates, to guarantee it or a neighbor contributes.
// For some lattices, you might need to try a handful of points in the
// cell,
// or flip a couple of coordinates, to guarantee it or a neighbor
// contributes.
// For An* lattices, the base coordinate seems fine.
double x0f = x0Skipped * context.xFrequency; double y0f = y0Skipped * context.yFrequency;
double x0f = x0Skipped * context.xFrequency;
double y0f = y0Skipped * context.yFrequency;
double x0s = context.orientation.s00 * x0f + context.orientation.s01 * y0f;
double y0s = context.orientation.s10 * x0f + context.orientation.s11 * y0f;
int x0sb = fastFloor(x0s), y0sb = fastFloor(y0s);
@ -287,11 +297,16 @@ public class OpenSimplex2S {
Grad2 grad = context.orientation.gradients[perm[perm[pxm] ^ pym]];
double gx = grad.dx * context.xFrequency;
double gy = grad.dy * context.yFrequency;
double gOff = 0.5 * (gx + gy); // to correct for (0.5, 0.5)-offset kernel
double gOff = 0.5 * (gx + gy); // to correct for (0.5, 0.5)-offset
// kernel
// Contribution kernel bounds
int yy0 = destPointY - scaledRadiusY; if (yy0 < y0Skipped) yy0 = y0Skipped;
int yy1 = destPointY + scaledRadiusY; if (yy1 > y0 + height) yy1 = y0 + height;
int yy0 = destPointY - scaledRadiusY;
if (yy0 < y0Skipped)
yy0 = y0Skipped;
int yy1 = destPointY + scaledRadiusY;
if (yy1 > y0 + height)
yy1 = y0 + height;
// For each row of the contribution circle,
for (int yy = yy0; yy < yy1; yy++) {
@ -300,16 +315,22 @@ public class OpenSimplex2S {
// Set up bounds so we only loop over what we need to
int thisScaledRadiusX = context.kernelBounds[ky];
int xx0 = destPointX - thisScaledRadiusX; if (xx0 < x0Skipped) xx0 = x0Skipped;
int xx1 = destPointX + thisScaledRadiusX; if (xx1 > x0 + width) xx1 = x0 + width;
int xx0 = destPointX - thisScaledRadiusX;
if (xx0 < x0Skipped)
xx0 = x0Skipped;
int xx1 = destPointX + thisScaledRadiusX;
if (xx1 > x0 + width)
xx1 = x0 + width;
// For each point on that row
for (int xx = xx0; xx < xx1; xx++) {
int dx = xx - destPointX;
int kx = dx + scaledRadiusX;
// gOff accounts for our choice to offset the pre-generated kernel by (0.5, 0.5) to avoid the zero center.
// I found almost no difference in performance using gOff vs not (under 1ns diff per value on my system)
// gOff accounts for our choice to offset the pre-generated
// kernel by (0.5, 0.5) to avoid the zero center.
// I found almost no difference in performance using gOff vs
// not (under 1ns diff per value on my system)
double extrapolation = gx * dx + gy * dy + gOff;
buffer[yy - y0][xx - x0] += kernel[ky][kx] * extrapolation;
@ -318,13 +339,14 @@ public class OpenSimplex2S {
// For each neighbor of the point
for (int i = 0; i < NEIGHBOR_MAP_2D.length; i++) {
AreaGenLatticePoint2D neighbor = new AreaGenLatticePoint2D(context,
point.xsv + NEIGHBOR_MAP_2D[i][0], point.ysv + NEIGHBOR_MAP_2D[i][1]);
AreaGenLatticePoint2D neighbor = new AreaGenLatticePoint2D(context, point.xsv + NEIGHBOR_MAP_2D[i][0],
point.ysv + NEIGHBOR_MAP_2D[i][1]);
// If it's in range of the buffer region and not seen before
if (neighbor.destPointX + scaledRadiusX >= x0Skipped && neighbor.destPointX - scaledRadiusX <= x0 + width - 1
&& neighbor.destPointY + scaledRadiusY >= y0Skipped && neighbor.destPointY - scaledRadiusY <= y0 + height - 1
&& !seen.contains(neighbor)) {
if (neighbor.destPointX + scaledRadiusX >= x0Skipped
&& neighbor.destPointX - scaledRadiusX <= x0 + width - 1
&& neighbor.destPointY + scaledRadiusY >= y0Skipped
&& neighbor.destPointY - scaledRadiusY <= y0 + height - 1 && !seen.contains(neighbor)) {
// Add it to the queue so we can process it at some point
queue.add(neighbor);
@ -337,9 +359,9 @@ public class OpenSimplex2S {
}
/**
* Generate the 3D noise over a large area/volume.
* Propagates by flood-fill instead of iterating over a range.
* Results may occasionally slightly exceed [-1, 1] due to the grid-snapped pre-generated kernel.
* Generate the 3D noise over a large area/volume. Propagates by flood-fill
* instead of iterating over a range. Results may occasionally slightly
* exceed [-1, 1] due to the grid-snapped pre-generated kernel.
*/
public void generate3(GenerateContext3D context, double[][][] buffer, int x0, int y0, int z0) {
int depth = buffer.length;
@ -349,11 +371,12 @@ public class OpenSimplex2S {
}
/**
* Generate the 3D noise over a large area/volume.
* Propagates by flood-fill instead of iterating over a range.
* Results may occasionally slightly exceed [-1, 1] due to the grid-snapped pre-generated kernel.
* Generate the 3D noise over a large area/volume. Propagates by flood-fill
* instead of iterating over a range. Results may occasionally slightly
* exceed [-1, 1] due to the grid-snapped pre-generated kernel.
*/
public void generate3(GenerateContext3D context, double[][][] buffer, int x0, int y0, int z0, int width, int height, int depth, int skipX, int skipY, int skipZ) {
public void generate3(GenerateContext3D context, double[][][] buffer, int x0, int y0, int z0, int width, int height,
int depth, int skipX, int skipY, int skipZ) {
Queue<AreaGenLatticePoint3D> queue = new LinkedList<AreaGenLatticePoint3D>();
Set<AreaGenLatticePoint3D> seen = new HashSet<AreaGenLatticePoint3D>();
@ -365,8 +388,10 @@ public class OpenSimplex2S {
// Quaternion multiplication for rotation.
// https://blog.molecular-matters.com/2013/05/24/a-faster-quaternion-vector-multiplication/
double qx = context.orientation.qx, qy = context.orientation.qy, qz = context.orientation.qz, qw = context.orientation.qw;
double x0f = x0Skipped * context.xFrequency, y0f = y0Skipped * context.yFrequency, z0f = z0Skipped * context.zFrequency;
double qx = context.orientation.qx, qy = context.orientation.qy, qz = context.orientation.qz,
qw = context.orientation.qw;
double x0f = x0Skipped * context.xFrequency, y0f = y0Skipped * context.yFrequency,
z0f = z0Skipped * context.zFrequency;
double tx = 2 * (qy * z0f - qz * y0f);
double ty = 2 * (qz * x0f - qx * z0f);
double tz = 2 * (qx * y0f - qy * x0f);
@ -392,11 +417,16 @@ public class OpenSimplex2S {
double gx = grad.dx * context.xFrequency;
double gy = grad.dy * context.yFrequency;
double gz = grad.dz * context.zFrequency;
double gOff = 0.5 * (gx + gy + gz); // to correct for (0.5, 0.5, 0.5)-offset kernel
double gOff = 0.5 * (gx + gy + gz); // to correct for (0.5, 0.5,
// 0.5)-offset kernel
// Contribution kernel bounds.
int zz0 = destPointZ - scaledRadiusZ; if (zz0 < z0Skipped) zz0 = z0Skipped;
int zz1 = destPointZ + scaledRadiusZ; if (zz1 > z0 + depth) zz1 = z0 + depth;
int zz0 = destPointZ - scaledRadiusZ;
if (zz0 < z0Skipped)
zz0 = z0Skipped;
int zz1 = destPointZ + scaledRadiusZ;
if (zz1 > z0 + depth)
zz1 = z0 + depth;
// For each x/y slice of the contribution sphere,
for (int zz = zz0; zz < zz1; zz++) {
@ -405,8 +435,12 @@ public class OpenSimplex2S {
// Set up bounds so we only loop over what we need to
int thisScaledRadiusY = context.kernelBoundsY[kz];
int yy0 = destPointY - thisScaledRadiusY; if (yy0 < y0Skipped) yy0 = y0Skipped;
int yy1 = destPointY + thisScaledRadiusY; if (yy1 > y0 + height) yy1 = y0 + height;
int yy0 = destPointY - thisScaledRadiusY;
if (yy0 < y0Skipped)
yy0 = y0Skipped;
int yy1 = destPointY + thisScaledRadiusY;
if (yy1 > y0 + height)
yy1 = y0 + height;
// For each row of the contribution circle,
for (int yy = yy0; yy < yy1; yy++) {
@ -415,15 +449,21 @@ public class OpenSimplex2S {
// Set up bounds so we only loop over what we need to
int thisScaledRadiusX = context.kernelBoundsX[kz][ky];
int xx0 = destPointX - thisScaledRadiusX; if (xx0 < x0Skipped) xx0 = x0Skipped;
int xx1 = destPointX + thisScaledRadiusX; if (xx1 > x0 + width) xx1 = x0 + width;
int xx0 = destPointX - thisScaledRadiusX;
if (xx0 < x0Skipped)
xx0 = x0Skipped;
int xx1 = destPointX + thisScaledRadiusX;
if (xx1 > x0 + width)
xx1 = x0 + width;
// For each point on that row
for (int xx = xx0; xx < xx1; xx++) {
int dx = xx - destPointX;
int kx = dx + scaledRadiusX;
// gOff accounts for our choice to offset the pre-generated kernel by (0.5, 0.5, 0.5) to avoid the zero center.
// gOff accounts for our choice to offset the
// pre-generated kernel by (0.5, 0.5, 0.5) to avoid the
// zero center.
double extrapolation = gx * dx + gy * dy + gz * dz + gOff;
buffer[zz - z0][yy - y0][xx - x0] += kernel[kz][ky][kx] * extrapolation;
@ -435,13 +475,16 @@ public class OpenSimplex2S {
for (int i = 0; i < NEIGHBOR_MAP_3D[0].length; i++) {
int l = point.lattice;
AreaGenLatticePoint3D neighbor = new AreaGenLatticePoint3D(context,
point.xsv + NEIGHBOR_MAP_3D[l][i][0], point.ysv + NEIGHBOR_MAP_3D[l][i][1], point.zsv + NEIGHBOR_MAP_3D[l][i][2], 1 ^ l);
point.xsv + NEIGHBOR_MAP_3D[l][i][0], point.ysv + NEIGHBOR_MAP_3D[l][i][1],
point.zsv + NEIGHBOR_MAP_3D[l][i][2], 1 ^ l);
// If it's in range of the buffer region and not seen before
if (neighbor.destPointX + scaledRadiusX >= x0Skipped && neighbor.destPointX - scaledRadiusX <= x0 + width - 1
&& neighbor.destPointY + scaledRadiusY >= y0Skipped && neighbor.destPointY - scaledRadiusY <= y0 + height - 1
&& neighbor.destPointZ + scaledRadiusZ >= z0Skipped && neighbor.destPointZ - scaledRadiusZ <= z0 + depth - 1
&& !seen.contains(neighbor)) {
if (neighbor.destPointX + scaledRadiusX >= x0Skipped
&& neighbor.destPointX - scaledRadiusX <= x0 + width - 1
&& neighbor.destPointY + scaledRadiusY >= y0Skipped
&& neighbor.destPointY - scaledRadiusY <= y0 + height - 1
&& neighbor.destPointZ + scaledRadiusZ >= z0Skipped
&& neighbor.destPointZ - scaledRadiusZ <= z0 + depth - 1 && !seen.contains(neighbor)) {
// Add it to the queue so we can process it at some point
queue.add(neighbor);
@ -458,7 +501,7 @@ public class OpenSimplex2S {
*/
private static int fastFloor(double x) {
int xi = (int)x;
int xi = (int) x;
return x < xi ? xi - 1 : xi;
}
@ -475,11 +518,35 @@ public class OpenSimplex2S {
for (int i = 0; i < 8; i++) {
int i1, j1, i2, j2;
if ((i & 1) == 0) {
if ((i & 2) == 0) { i1 = -1; j1 = 0; } else { i1 = 1; j1 = 0; }
if ((i & 4) == 0) { i2 = 0; j2 = -1; } else { i2 = 0; j2 = 1; }
if ((i & 2) == 0) {
i1 = -1;
j1 = 0;
} else {
if ((i & 2) != 0) { i1 = 2; j1 = 1; } else { i1 = 0; j1 = 1; }
if ((i & 4) != 0) { i2 = 1; j2 = 2; } else { i2 = 1; j2 = 0; }
i1 = 1;
j1 = 0;
}
if ((i & 4) == 0) {
i2 = 0;
j2 = -1;
} else {
i2 = 0;
j2 = 1;
}
} else {
if ((i & 2) != 0) {
i1 = 2;
j1 = 1;
} else {
i1 = 0;
j1 = 1;
}
if ((i & 4) != 0) {
i2 = 1;
j2 = 2;
} else {
i2 = 1;
j2 = 0;
}
}
LOOKUP_2D[i * 4 + 0] = new LatticePoint2D(0, 0);
LOOKUP_2D[i * 4 + 1] = new LatticePoint2D(1, 1);
@ -489,10 +556,15 @@ public class OpenSimplex2S {
for (int i = 0; i < 8; i++) {
int i1, j1, k1, i2, j2, k2;
i1 = (i >> 0) & 1; j1 = (i >> 1) & 1; k1 = (i >> 2) & 1;
i2 = i1 ^ 1; j2 = j1 ^ 1; k2 = k1 ^ 1;
i1 = (i >> 0) & 1;
j1 = (i >> 1) & 1;
k1 = (i >> 2) & 1;
i2 = i1 ^ 1;
j2 = j1 ^ 1;
k2 = k1 ^ 1;
// The two points within this octant, one from each of the two cubic half-lattices.
// The two points within this octant, one from each of the two cubic
// half-lattices.
LatticePoint3D c0 = new LatticePoint3D(i1, j1, k1, 0);
LatticePoint3D c1 = new LatticePoint3D(i1 + i2, j1 + j2, k1 + k2, 1);
@ -525,27 +597,36 @@ public class OpenSimplex2S {
c1.nextOnFailure = c1.nextOnSuccess = c2;
// If c2 is in range, then we know c3 and c4 are not.
c2.nextOnFailure = c3; c2.nextOnSuccess = c5;
c3.nextOnFailure = c4; c3.nextOnSuccess = c4;
c2.nextOnFailure = c3;
c2.nextOnSuccess = c5;
c3.nextOnFailure = c4;
c3.nextOnSuccess = c4;
// If c4 is in range, then we know c5 is not.
c4.nextOnFailure = c5; c4.nextOnSuccess = c6;
c4.nextOnFailure = c5;
c4.nextOnSuccess = c6;
c5.nextOnFailure = c5.nextOnSuccess = c6;
// If c6 is in range, then we know c7 and c8 are not.
c6.nextOnFailure = c7; c6.nextOnSuccess = c9;
c7.nextOnFailure = c8; c7.nextOnSuccess = c8;
c6.nextOnFailure = c7;
c6.nextOnSuccess = c9;
c7.nextOnFailure = c8;
c7.nextOnSuccess = c8;
// If c8 is in range, then we know c9 is not.
c8.nextOnFailure = c9; c8.nextOnSuccess = cA;
c8.nextOnFailure = c9;
c8.nextOnSuccess = cA;
c9.nextOnFailure = c9.nextOnSuccess = cA;
// If cA is in range, then we know cB and cC are not.
cA.nextOnFailure = cB; cA.nextOnSuccess = cD;
cB.nextOnFailure = cC; cB.nextOnSuccess = cC;
cA.nextOnFailure = cB;
cA.nextOnSuccess = cD;
cB.nextOnFailure = cC;
cB.nextOnSuccess = cC;
// If cC is in range, then we know cD is not.
cC.nextOnFailure = cD; cC.nextOnSuccess = null;
cC.nextOnFailure = cD;
cC.nextOnSuccess = null;
cD.nextOnFailure = cD.nextOnSuccess = null;
LOOKUP_3D[i] = c0;
@ -554,28 +635,24 @@ public class OpenSimplex2S {
}
// Hexagon surrounding each vertex.
private static final int[][] NEIGHBOR_MAP_2D = {
{ 1, 0 }, { 1, 1 }, { 0, 1 }, { 0, -1 }, { -1, -1 }, { -1, 0 }
};
private static final int[][] NEIGHBOR_MAP_2D = { { 1, 0 }, { 1, 1 }, { 0, 1 }, { 0, -1 }, { -1, -1 }, { -1, 0 } };
// Cube surrounding each vertex.
// Alternates between half-lattices.
private static final int[][][] NEIGHBOR_MAP_3D = {
{
{ 1024, 1024, 1024 }, { 1025, 1024, 1024 }, { 1024, 1025, 1024 }, { 1025, 1025, 1024 },
{ 1024, 1024, 1025 }, { 1025, 1024, 1025 }, { 1024, 1025, 1025 }, { 1025, 1025, 1025 }
},
{
{ -1024, -1024, -1024 }, { -1025, -1024, 1024 }, { -1024, -1025, -1024 }, { -1025, -1025, -1024 },
{ -1024, -1024, -1025 }, { -1025, -1024, -1025 }, { -1024, -1025, -1025 }, { -1025, -1025, 1025 }
},
};
{ { 1024, 1024, 1024 }, { 1025, 1024, 1024 }, { 1024, 1025, 1024 }, { 1025, 1025, 1024 },
{ 1024, 1024, 1025 }, { 1025, 1024, 1025 }, { 1024, 1025, 1025 }, { 1025, 1025, 1025 } },
{ { -1024, -1024, -1024 }, { -1025, -1024, 1024 }, { -1024, -1025, -1024 }, { -1025, -1025, -1024 },
{ -1024, -1024, -1025 }, { -1025, -1024, -1025 }, { -1024, -1025, -1025 },
{ -1025, -1025, 1025 } }, };
private static class LatticePoint2D {
int xsv, ysv;
double dx, dy;
public LatticePoint2D(int xsv, int ysv) {
this.xsv = xsv; this.ysv = ysv;
this.xsv = xsv;
this.ysv = ysv;
double ssv = (xsv + ysv) * -0.211324865405187;
this.dx = -xsv - ssv;
this.dy = -ysv - ssv;
@ -586,29 +663,42 @@ public class OpenSimplex2S {
public double dxr, dyr, dzr;
public int xrv, yrv, zrv;
LatticePoint3D nextOnFailure, nextOnSuccess;
public LatticePoint3D(int xrv, int yrv, int zrv, int lattice) {
this.dxr = -xrv + lattice * 0.5; this.dyr = -yrv + lattice * 0.5; this.dzr = -zrv + lattice * 0.5;
this.xrv = xrv + lattice * 1024; this.yrv = yrv + lattice * 1024; this.zrv = zrv + lattice * 1024;
this.dxr = -xrv + lattice * 0.5;
this.dyr = -yrv + lattice * 0.5;
this.dzr = -zrv + lattice * 0.5;
this.xrv = xrv + lattice * 1024;
this.yrv = yrv + lattice * 1024;
this.zrv = zrv + lattice * 1024;
}
}
private static class AreaGenLatticePoint2D {
int xsv, ysv;
int destPointX, destPointY;
public AreaGenLatticePoint2D(GenerateContext2D context, int xsv, int ysv) {
this.xsv = xsv; this.ysv = ysv;
//Matrix multiplication for inverse rotation. Simplex skew transforms have always been shorthand for matrices.
this.destPointX = (int)Math.ceil((context.orientation.t00 * xsv + context.orientation.t01 * ysv) * context.xFrequencyInverse);
this.destPointY = (int)Math.ceil((context.orientation.t10 * xsv + context.orientation.t11 * ysv) * context.yFrequencyInverse);
public AreaGenLatticePoint2D(GenerateContext2D context, int xsv, int ysv) {
this.xsv = xsv;
this.ysv = ysv;
// Matrix multiplication for inverse rotation. Simplex skew
// transforms have always been shorthand for matrices.
this.destPointX = (int) Math
.ceil((context.orientation.t00 * xsv + context.orientation.t01 * ysv) * context.xFrequencyInverse);
this.destPointY = (int) Math
.ceil((context.orientation.t10 * xsv + context.orientation.t11 * ysv) * context.yFrequencyInverse);
}
@Override
public int hashCode() {
return xsv * 7841 + ysv;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof AreaGenLatticePoint2D)) return false;
if (!(obj instanceof AreaGenLatticePoint2D))
return false;
AreaGenLatticePoint2D other = (AreaGenLatticePoint2D) obj;
return (other.xsv == this.xsv && other.ysv == this.ysv);
}
@ -617,15 +707,20 @@ public class OpenSimplex2S {
private static class AreaGenLatticePoint3D {
int xsv, ysv, zsv, lattice;
int destPointX, destPointY, destPointZ;
public AreaGenLatticePoint3D(GenerateContext3D context, int xsv, int ysv, int zsv, int lattice) {
this.xsv = xsv; this.ysv = ysv; this.zsv = zsv; this.lattice = lattice;
this.xsv = xsv;
this.ysv = ysv;
this.zsv = zsv;
this.lattice = lattice;
double xr = (xsv - lattice * 1024.5);
double yr = (ysv - lattice * 1024.5);
double zr = (zsv - lattice * 1024.5);
// Quaternion multiplication for inverse rotation.
// https://blog.molecular-matters.com/2013/05/24/a-faster-quaternion-vector-multiplication/
double qx = -context.orientation.qx, qy = -context.orientation.qy, qz = -context.orientation.qz, qw = context.orientation.qw;
double qx = -context.orientation.qx, qy = -context.orientation.qy, qz = -context.orientation.qz,
qw = context.orientation.qw;
double tx = 2 * (qy * zr - qz * yr);
double ty = 2 * (qz * xr - qx * zr);
double tz = 2 * (qx * yr - qy * xr);
@ -633,19 +728,23 @@ public class OpenSimplex2S {
double yrr = yr + qw * ty + (qz * tx - qx * tz);
double zrr = zr + qw * tz + (qx * ty - qy * tx);
this.destPointX = (int)Math.ceil(xrr * context.xFrequencyInverse);
this.destPointY = (int)Math.ceil(yrr * context.yFrequencyInverse);
this.destPointZ = (int)Math.ceil(zrr * context.zFrequencyInverse);
this.destPointX = (int) Math.ceil(xrr * context.xFrequencyInverse);
this.destPointY = (int) Math.ceil(yrr * context.yFrequencyInverse);
this.destPointZ = (int) Math.ceil(zrr * context.zFrequencyInverse);
}
@Override
public int hashCode() {
return xsv * 2122193 + ysv * 2053 + zsv * 2 + lattice;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof AreaGenLatticePoint3D)) return false;
if (!(obj instanceof AreaGenLatticePoint3D))
return false;
AreaGenLatticePoint3D other = (AreaGenLatticePoint3D) obj;
return (other.xsv == this.xsv && other.ysv == this.ysv && other.zsv == this.zsv && other.lattice == this.lattice);
return (other.xsv == this.xsv && other.ysv == this.ysv && other.zsv == this.zsv
&& other.lattice == this.lattice);
}
}
@ -661,7 +760,8 @@ public class OpenSimplex2S {
int[] kernelBounds;
LatticeOrientation2D orientation;
public GenerateContext2D(LatticeOrientation2D orientation, double xFrequency, double yFrequency, double amplitude) {
public GenerateContext2D(LatticeOrientation2D orientation, double xFrequency, double yFrequency,
double amplitude) {
// These will be used by every call to generate
this.orientation = orientation;
@ -674,19 +774,18 @@ public class OpenSimplex2S {
double preciseScaledRadiusY = Math.sqrt(2.0 / 3.0) * yFrequencyInverse;
// 0.25 because we offset center by 0.5
this.scaledRadiusX = (int)Math.ceil(preciseScaledRadiusX + 0.25);
this.scaledRadiusY = (int)Math.ceil(preciseScaledRadiusY + 0.25);
this.scaledRadiusX = (int) Math.ceil(preciseScaledRadiusX + 0.25);
this.scaledRadiusY = (int) Math.ceil(preciseScaledRadiusY + 0.25);
// So will these
kernel = new double[scaledRadiusY/* * 2*/][];
kernel = new double[scaledRadiusY/* * 2 */][];
kernelBounds = new int[scaledRadiusY * 2];
for (int yy = 0; yy < scaledRadiusY * 2; yy++) {
// Pre-generate boundary of circle
kernelBounds[yy] = (int)Math.ceil(
Math.sqrt(1.0
- (yy + 0.5 - scaledRadiusY) * (yy + 0.5 - scaledRadiusY) / (scaledRadiusY * scaledRadiusY)
) * scaledRadiusX);
kernelBounds[yy] = (int) Math.ceil(Math.sqrt(
1.0 - (yy + 0.5 - scaledRadiusY) * (yy + 0.5 - scaledRadiusY) / (scaledRadiusY * scaledRadiusY))
* scaledRadiusX);
if (yy < scaledRadiusY) {
kernel[yy] = new double[scaledRadiusX * 2];
@ -703,7 +802,7 @@ public class OpenSimplex2S {
kernel[yy][xx] = 0.0;
}
}
} /* else kernel[yy] = kernel[2 * scaledRadiusY - yy - 1];*/
} /* else kernel[yy] = kernel[2 * scaledRadiusY - yy - 1]; */
}
}
}
@ -724,7 +823,8 @@ public class OpenSimplex2S {
int[][] kernelBoundsX;
LatticeOrientation3D orientation;
public GenerateContext3D(LatticeOrientation3D orientation, double xFrequency, double yFrequency, double zFrequency, double amplitude) {
public GenerateContext3D(LatticeOrientation3D orientation, double xFrequency, double yFrequency,
double zFrequency, double amplitude) {
// These will be used by every call to generate
this.orientation = orientation;
@ -740,9 +840,9 @@ public class OpenSimplex2S {
double preciseScaledRadiusZ = Math.sqrt(0.75) * zFrequencyInverse;
// 0.25 because we offset center by 0.5
this.scaledRadiusX = (int)Math.ceil(preciseScaledRadiusX + 0.25);
this.scaledRadiusY = (int)Math.ceil(preciseScaledRadiusY + 0.25);
this.scaledRadiusZ = (int)Math.ceil(preciseScaledRadiusZ + 0.25);
this.scaledRadiusX = (int) Math.ceil(preciseScaledRadiusX + 0.25);
this.scaledRadiusY = (int) Math.ceil(preciseScaledRadiusY + 0.25);
this.scaledRadiusZ = (int) Math.ceil(preciseScaledRadiusZ + 0.25);
// So will these
kernel = new double[scaledRadiusZ * 2][][];
@ -751,9 +851,9 @@ public class OpenSimplex2S {
for (int zz = 0; zz < scaledRadiusZ * 2; zz++) {
// Pre-generate boundary of sphere
kernelBoundsY[zz] = (int)Math.ceil(
Math.sqrt(1.0 - (zz + 0.5 - scaledRadiusZ) * (zz + 0.5 - scaledRadiusZ)
/ (scaledRadiusZ * scaledRadiusZ)) * scaledRadiusY);
kernelBoundsY[zz] = (int) Math.ceil(Math.sqrt(
1.0 - (zz + 0.5 - scaledRadiusZ) * (zz + 0.5 - scaledRadiusZ) / (scaledRadiusZ * scaledRadiusZ))
* scaledRadiusY);
if (zz < scaledRadiusZ) {
kernel[zz] = new double[scaledRadiusY * 2][];
@ -767,11 +867,12 @@ public class OpenSimplex2S {
for (int yy = 0; yy < scaledRadiusY * 2; yy++) {
// Pre-generate boundary of sphere
kernelBoundsX[zz][yy] = (int)Math.ceil(
Math.sqrt(1.0
- (yy + 0.5 - scaledRadiusY) * (yy + 0.5 - scaledRadiusY) / (scaledRadiusY * scaledRadiusY)
- (zz + 0.5 - scaledRadiusZ) * (zz + 0.5 - scaledRadiusZ) / (scaledRadiusZ * scaledRadiusZ)
) * scaledRadiusX);
kernelBoundsX[zz][yy] = (int) Math.ceil(Math.sqrt(1.0
- (yy + 0.5 - scaledRadiusY) * (yy + 0.5 - scaledRadiusY)
/ (scaledRadiusY * scaledRadiusY)
- (zz + 0.5 - scaledRadiusZ) * (zz + 0.5 - scaledRadiusZ)
/ (scaledRadiusZ * scaledRadiusZ))
* scaledRadiusX);
if (yy < scaledRadiusY) {
kernel[zz][yy] = new double[scaledRadiusX * 2];
@ -790,7 +891,8 @@ public class OpenSimplex2S {
}
}
} else kernel[zz][yy] = kernel[zz][2 * scaledRadiusY - yy - 1];
} else
kernel[zz][yy] = kernel[zz][2 * scaledRadiusY - yy - 1];
}
}
}
@ -798,40 +900,50 @@ public class OpenSimplex2S {
}
public enum LatticeOrientation2D {
// Simplex skew transforms have always been shorthand for the matrices they represent.
// But when we bake the rotation into the skew transform, we need to use the general form.
Standard(GRADIENTS_2D,
1.366025403784439, 0.366025403784439, 0.366025403784439, 1.366025403784439,
0.788675134594813, -0.211324865405187, -0.211324865405187, 0.788675134594813),
XBeforeY(GRADIENTS_2D_X_BEFORE_Y,
0.7071067811865476, 1.224744871380249, -0.7071067811865476, 1.224744871380249,
0.7071067811865476, -0.7071067811865476, 0.40824829046764305, 0.40824829046764305);
// Simplex skew transforms have always been shorthand for the matrices
// they represent.
// But when we bake the rotation into the skew transform, we need to use
// the general form.
Standard(GRADIENTS_2D, 1.366025403784439, 0.366025403784439, 0.366025403784439, 1.366025403784439,
0.788675134594813, -0.211324865405187, -0.211324865405187,
0.788675134594813), XBeforeY(GRADIENTS_2D_X_BEFORE_Y, 0.7071067811865476, 1.224744871380249,
-0.7071067811865476, 1.224744871380249, 0.7071067811865476, -0.7071067811865476,
0.40824829046764305, 0.40824829046764305);
Grad2[] gradients;
double s00, s01, s10, s11;
double t00, t01, t10, t11;
private LatticeOrientation2D(Grad2[] gradients,
double s00, double s01, double s10, double s11,
double t00, double t01, double t10, double t11) {
private LatticeOrientation2D(Grad2[] gradients, double s00, double s01, double s10, double s11, double t00,
double t01, double t10, double t11) {
this.gradients = gradients;
this.s00 = s00; this.s01 = s01; this.s10 = s10; this.s11 = s11;
this.t00 = t00; this.t01 = t01; this.t10 = t10; this.t11 = t11;
this.s00 = s00;
this.s01 = s01;
this.s10 = s10;
this.s11 = s11;
this.t00 = t00;
this.t01 = t01;
this.t10 = t10;
this.t11 = t11;
}
}
public enum LatticeOrientation3D {
// Quaternions for 3D. Could use matrices, but I already wrote this code before I moved them into here.
Classic(GRADIENTS_3D_CLASSIC, 0.577350269189626, 0.577350269189626, 0.577350269189626, 0),
XYBeforeZ(GRADIENTS_3D_XY_BEFORE_Z, 0.3250575836718682, -0.3250575836718682, 0, 0.8880738339771154),
XZBeforeY(GRADIENTS_3D_XZ_BEFORE_Y, -0.3250575836718682, 0, 0.3250575836718682, 0.8880738339771154);
// Quaternions for 3D. Could use matrices, but I already wrote this code
// before I moved them into here.
Classic(GRADIENTS_3D_CLASSIC, 0.577350269189626, 0.577350269189626, 0.577350269189626, 0), XYBeforeZ(
GRADIENTS_3D_XY_BEFORE_Z, 0.3250575836718682, -0.3250575836718682, 0, 0.8880738339771154), XZBeforeY(
GRADIENTS_3D_XZ_BEFORE_Y, -0.3250575836718682, 0, 0.3250575836718682, 0.8880738339771154);
Grad3[] gradients;
double qx, qy, qz, qw;
private LatticeOrientation3D(Grad3[] gradients, double qx, double qy, double qz, double qw) {
this.gradients = gradients;
this.qx = qx; this.qy = qy; this.qz = qz; this.qw = qw;
this.qx = qx;
this.qy = qy;
this.qz = qz;
this.qw = qw;
}
}
@ -841,15 +953,20 @@ public class OpenSimplex2S {
public static class Grad2 {
double dx, dy;
public Grad2(double dx, double dy) {
this.dx = dx; this.dy = dy;
this.dx = dx;
this.dy = dy;
}
}
public static class Grad3 {
double dx, dy, dz;
public Grad3(double dx, double dy, double dz) {
this.dx = dx; this.dy = dy; this.dz = dz;
this.dx = dx;
this.dy = dy;
this.dz = dz;
}
}
@ -861,35 +978,23 @@ public class OpenSimplex2S {
GRADIENTS_2D = new Grad2[PSIZE];
GRADIENTS_2D_X_BEFORE_Y = new Grad2[PSIZE];
Grad2[] grad2 = {
new Grad2( 0.130526192220052, 0.99144486137381),
new Grad2( 0.38268343236509, 0.923879532511287),
new Grad2( 0.608761429008721, 0.793353340291235),
new Grad2( 0.793353340291235, 0.608761429008721),
new Grad2( 0.923879532511287, 0.38268343236509),
new Grad2( 0.99144486137381, 0.130526192220051),
new Grad2( 0.99144486137381, -0.130526192220051),
new Grad2( 0.923879532511287, -0.38268343236509),
new Grad2( 0.793353340291235, -0.60876142900872),
new Grad2( 0.608761429008721, -0.793353340291235),
new Grad2( 0.38268343236509, -0.923879532511287),
new Grad2( 0.130526192220052, -0.99144486137381),
new Grad2(-0.130526192220052, -0.99144486137381),
new Grad2(-0.38268343236509, -0.923879532511287),
new Grad2(-0.608761429008721, -0.793353340291235),
new Grad2(-0.793353340291235, -0.608761429008721),
new Grad2(-0.923879532511287, -0.38268343236509),
new Grad2(-0.99144486137381, -0.130526192220052),
new Grad2(-0.99144486137381, 0.130526192220051),
new Grad2(-0.923879532511287, 0.38268343236509),
new Grad2(-0.793353340291235, 0.608761429008721),
new Grad2(-0.608761429008721, 0.793353340291235),
new Grad2(-0.38268343236509, 0.923879532511287),
new Grad2(-0.130526192220052, 0.99144486137381)
};
Grad2[] grad2 = { new Grad2(0.130526192220052, 0.99144486137381),
new Grad2(0.38268343236509, 0.923879532511287), new Grad2(0.608761429008721, 0.793353340291235),
new Grad2(0.793353340291235, 0.608761429008721), new Grad2(0.923879532511287, 0.38268343236509),
new Grad2(0.99144486137381, 0.130526192220051), new Grad2(0.99144486137381, -0.130526192220051),
new Grad2(0.923879532511287, -0.38268343236509), new Grad2(0.793353340291235, -0.60876142900872),
new Grad2(0.608761429008721, -0.793353340291235), new Grad2(0.38268343236509, -0.923879532511287),
new Grad2(0.130526192220052, -0.99144486137381), new Grad2(-0.130526192220052, -0.99144486137381),
new Grad2(-0.38268343236509, -0.923879532511287), new Grad2(-0.608761429008721, -0.793353340291235),
new Grad2(-0.793353340291235, -0.608761429008721), new Grad2(-0.923879532511287, -0.38268343236509),
new Grad2(-0.99144486137381, -0.130526192220052), new Grad2(-0.99144486137381, 0.130526192220051),
new Grad2(-0.923879532511287, 0.38268343236509), new Grad2(-0.793353340291235, 0.608761429008721),
new Grad2(-0.608761429008721, 0.793353340291235), new Grad2(-0.38268343236509, 0.923879532511287),
new Grad2(-0.130526192220052, 0.99144486137381) };
Grad2[] grad2XBeforeY = new Grad2[grad2.length];
for (int i = 0; i < grad2.length; i++) {
grad2[i].dx /= N2; grad2[i].dy /= N2;
grad2[i].dx /= N2;
grad2[i].dy /= N2;
// Unrotated gradients for XBeforeY 2D
double xx = grad2[i].dx * 0.7071067811865476;
@ -905,77 +1010,59 @@ public class OpenSimplex2S {
GRADIENTS_3D_CLASSIC = new Grad3[PSIZE];
GRADIENTS_3D_XY_BEFORE_Z = new Grad3[PSIZE];
GRADIENTS_3D_XZ_BEFORE_Y = new Grad3[PSIZE];
Grad3[] grad3 = {
new Grad3(-2.22474487139, -2.22474487139, -1.0),
Grad3[] grad3 = { new Grad3(-2.22474487139, -2.22474487139, -1.0),
new Grad3(-2.22474487139, -2.22474487139, 1.0),
new Grad3(-3.0862664687972017, -1.1721513422464978, 0.0),
new Grad3(-1.1721513422464978, -3.0862664687972017, 0.0),
new Grad3(-2.22474487139, -1.0, -2.22474487139),
new Grad3(-2.22474487139, 1.0, -2.22474487139),
new Grad3(-2.22474487139, -1.0, -2.22474487139), new Grad3(-2.22474487139, 1.0, -2.22474487139),
new Grad3(-1.1721513422464978, 0.0, -3.0862664687972017),
new Grad3(-3.0862664687972017, 0.0, -1.1721513422464978),
new Grad3(-2.22474487139, -1.0, 2.22474487139),
new Grad3(-2.22474487139, 1.0, 2.22474487139),
new Grad3(-2.22474487139, -1.0, 2.22474487139), new Grad3(-2.22474487139, 1.0, 2.22474487139),
new Grad3(-3.0862664687972017, 0.0, 1.1721513422464978),
new Grad3(-1.1721513422464978, 0.0, 3.0862664687972017),
new Grad3(-2.22474487139, 2.22474487139, -1.0),
new Grad3(-2.22474487139, 2.22474487139, 1.0),
new Grad3(-1.1721513422464978, 3.0862664687972017, 0.0),
new Grad3(-1.1721513422464978, 0.0, 3.0862664687972017), new Grad3(-2.22474487139, 2.22474487139, -1.0),
new Grad3(-2.22474487139, 2.22474487139, 1.0), new Grad3(-1.1721513422464978, 3.0862664687972017, 0.0),
new Grad3(-3.0862664687972017, 1.1721513422464978, 0.0),
new Grad3(-1.0, -2.22474487139, -2.22474487139),
new Grad3( 1.0, -2.22474487139, -2.22474487139),
new Grad3( 0.0, -3.0862664687972017, -1.1721513422464978),
new Grad3( 0.0, -1.1721513422464978, -3.0862664687972017),
new Grad3(-1.0, -2.22474487139, 2.22474487139),
new Grad3( 1.0, -2.22474487139, 2.22474487139),
new Grad3( 0.0, -1.1721513422464978, 3.0862664687972017),
new Grad3( 0.0, -3.0862664687972017, 1.1721513422464978),
new Grad3(-1.0, 2.22474487139, -2.22474487139),
new Grad3( 1.0, 2.22474487139, -2.22474487139),
new Grad3( 0.0, 1.1721513422464978, -3.0862664687972017),
new Grad3( 0.0, 3.0862664687972017, -1.1721513422464978),
new Grad3(-1.0, 2.22474487139, 2.22474487139),
new Grad3( 1.0, 2.22474487139, 2.22474487139),
new Grad3( 0.0, 3.0862664687972017, 1.1721513422464978),
new Grad3( 0.0, 1.1721513422464978, 3.0862664687972017),
new Grad3( 2.22474487139, -2.22474487139, -1.0),
new Grad3( 2.22474487139, -2.22474487139, 1.0),
new Grad3( 1.1721513422464978, -3.0862664687972017, 0.0),
new Grad3( 3.0862664687972017, -1.1721513422464978, 0.0),
new Grad3( 2.22474487139, -1.0, -2.22474487139),
new Grad3( 2.22474487139, 1.0, -2.22474487139),
new Grad3( 3.0862664687972017, 0.0, -1.1721513422464978),
new Grad3( 1.1721513422464978, 0.0, -3.0862664687972017),
new Grad3( 2.22474487139, -1.0, 2.22474487139),
new Grad3( 2.22474487139, 1.0, 2.22474487139),
new Grad3( 1.1721513422464978, 0.0, 3.0862664687972017),
new Grad3( 3.0862664687972017, 0.0, 1.1721513422464978),
new Grad3( 2.22474487139, 2.22474487139, -1.0),
new Grad3( 2.22474487139, 2.22474487139, 1.0),
new Grad3( 3.0862664687972017, 1.1721513422464978, 0.0),
new Grad3( 1.1721513422464978, 3.0862664687972017, 0.0)
};
new Grad3(-1.0, -2.22474487139, -2.22474487139), new Grad3(1.0, -2.22474487139, -2.22474487139),
new Grad3(0.0, -3.0862664687972017, -1.1721513422464978),
new Grad3(0.0, -1.1721513422464978, -3.0862664687972017),
new Grad3(-1.0, -2.22474487139, 2.22474487139), new Grad3(1.0, -2.22474487139, 2.22474487139),
new Grad3(0.0, -1.1721513422464978, 3.0862664687972017),
new Grad3(0.0, -3.0862664687972017, 1.1721513422464978), new Grad3(-1.0, 2.22474487139, -2.22474487139),
new Grad3(1.0, 2.22474487139, -2.22474487139), new Grad3(0.0, 1.1721513422464978, -3.0862664687972017),
new Grad3(0.0, 3.0862664687972017, -1.1721513422464978), new Grad3(-1.0, 2.22474487139, 2.22474487139),
new Grad3(1.0, 2.22474487139, 2.22474487139), new Grad3(0.0, 3.0862664687972017, 1.1721513422464978),
new Grad3(0.0, 1.1721513422464978, 3.0862664687972017), new Grad3(2.22474487139, -2.22474487139, -1.0),
new Grad3(2.22474487139, -2.22474487139, 1.0), new Grad3(1.1721513422464978, -3.0862664687972017, 0.0),
new Grad3(3.0862664687972017, -1.1721513422464978, 0.0), new Grad3(2.22474487139, -1.0, -2.22474487139),
new Grad3(2.22474487139, 1.0, -2.22474487139), new Grad3(3.0862664687972017, 0.0, -1.1721513422464978),
new Grad3(1.1721513422464978, 0.0, -3.0862664687972017), new Grad3(2.22474487139, -1.0, 2.22474487139),
new Grad3(2.22474487139, 1.0, 2.22474487139), new Grad3(1.1721513422464978, 0.0, 3.0862664687972017),
new Grad3(3.0862664687972017, 0.0, 1.1721513422464978), new Grad3(2.22474487139, 2.22474487139, -1.0),
new Grad3(2.22474487139, 2.22474487139, 1.0), new Grad3(3.0862664687972017, 1.1721513422464978, 0.0),
new Grad3(1.1721513422464978, 3.0862664687972017, 0.0) };
Grad3[] grad3Classic = new Grad3[grad3.length];
Grad3[] grad3XYBeforeZ = new Grad3[grad3.length];
Grad3[] grad3XZBeforeY = new Grad3[grad3.length];
for (int i = 0; i < grad3.length; i++) {
grad3[i].dx /= N3; grad3[i].dy /= N3; grad3[i].dz /= N3;
grad3[i].dx /= N3;
grad3[i].dy /= N3;
grad3[i].dz /= N3;
double gxr = grad3[i].dx, gyr = grad3[i].dy, gzr = grad3[i].dz;
// Unrotated gradients for classic 3D
double grr = (2.0 / 3.0) * (gxr + gyr + gzr);
// double dx = grr - gxr, dy = grr - gyr, dz = grr - gzr;
grad3Classic[i] = new Grad3( grr - gxr, grr - gyr, grr - gzr );
// double dx = grr - gxr, dy = grr - gyr, dz = grr - gzr;
grad3Classic[i] = new Grad3(grr - gxr, grr - gyr, grr - gzr);
// Unrotated gradients for XYBeforeZ 3D
double s2 = (gxr + gyr) * -0.211324865405187;
double zz = gzr * 0.577350269189626;
grad3XYBeforeZ[i] = new Grad3( gxr + s2 + zz, gyr + s2 + zz, (gzr - gxr - gyr) * 0.577350269189626 );
grad3XYBeforeZ[i] = new Grad3(gxr + s2 + zz, gyr + s2 + zz, (gzr - gxr - gyr) * 0.577350269189626);
// Unrotated gradients for plane-first 3D
s2 = (gxr + gzr) * -0.211324865405187;
double yy = gyr * 0.577350269189626;
grad3XZBeforeY[i] = new Grad3( gxr + s2 + yy, (gyr - gxr - gzr) * 0.577350269189626, gzr + s2 + yy );
grad3XZBeforeY[i] = new Grad3(gxr + s2 + yy, (gyr - gxr - gzr) * 0.577350269189626, gzr + s2 + yy);
}
for (int i = 0; i < PSIZE; i++) {
GRADIENTS_3D[i] = grad3[i % grad3.length];

View File

@ -611,8 +611,7 @@ public class ArrayUtil {
int end = offset + length;
if (end > arrayLength || offset < 0)
throw new IllegalArgumentException(
"Array contains [0; " + arrayLength + "), requested [" + offset + "; " + end + ")"
);
"Array contains [0; " + arrayLength + "), requested [" + offset + "; " + end + ")");
return length;
}
@ -628,8 +627,7 @@ public class ArrayUtil {
if (end > arrayLength || start < 0)
throw new IllegalArgumentException(
"Array contains [0; " + arrayLength + "), requested [" + start + "; " + end + ")"
);
"Array contains [0; " + arrayLength + "), requested [" + start + "; " + end + ")");
return end;
}

View File

@ -1,45 +0,0 @@
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil;
public class ConstantsMapException extends RuntimeException {
private static final long serialVersionUID = -4298704891780063127L;
public ConstantsMapException() {
}
public ConstantsMapException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public ConstantsMapException(String message, Throwable cause) {
super(message, cause);
}
public ConstantsMapException(String message) {
super(message);
}
public ConstantsMapException(Throwable cause) {
super(cause);
}
}

View File

@ -1,307 +0,0 @@
/*
* JPUtil
* Copyright (C) 2019-2022 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntPredicate;
import java.util.function.Predicate;
import java.util.regex.Pattern;
public class IntConstantsMap {
private final Map<Integer, String> namesByValue;
private final Map<String, Integer> valuesByName;
protected IntConstantsMap(Map<Integer, String> namesByValue, Map<String, Integer> valuesByName) {
this.namesByValue = namesByValue;
this.valuesByName = valuesByName;
}
public int getValue(String name) {
Integer value = valuesByName.get(name);
if (value == null) {
throw new NoSuchElementException("No constant with name " + name);
}
return value.intValue();
}
public boolean hasConstant(String name) {
return valuesByName.containsKey(name);
}
public String getName(int value) {
String name = namesByValue.get(value);
if (name == null) {
throw new NoSuchElementException("No constant with value " + value);
}
return name;
}
public boolean hasConstant(int value) {
return namesByValue.containsKey(value);
}
public Map<String, Integer> getAll() {
return valuesByName;
}
@Override
public String toString() {
return valuesByName.toString();
}
public static Builder from(Class<?> clazz) {
return new Builder(clazz);
}
public static class Builder {
@FunctionalInterface
public static interface Filter {
boolean test(String name, int value);
}
public class ConstantSpec {
public String name;
public int value;
public void drop() {
if (!extra.contains(name)) {
name = null;
}
}
}
private final List<Consumer<ConstantSpec>> transforms = new ArrayList<>();
private final Set<String> extra = new HashSet<>();
private final Class<?> source;
public Builder(Class<?> source) {
this.source = source;
}
public Builder apply(Consumer<ConstantSpec> transform) {
transforms.add(transform);
return this;
}
public Builder only(Filter filter) {
return apply(s -> {
if (!filter.test(s.name, s.value)) {
s.drop();
}
});
}
public Builder only(Predicate<String> nameFilter) {
return apply(s -> {
if (!nameFilter.test(s.name)) {
s.drop();
}
});
}
public Builder onlyValued(IntPredicate valueFilter) {
return apply(s -> {
if (!valueFilter.test(s.value)) {
s.drop();
}
});
}
public Builder regex(String regex) {
return only(Pattern.compile(regex).asPredicate());
}
public Builder prefix(String prefix) {
return only(n -> n.startsWith(prefix) && n.length() > prefix.length());
}
public Builder exclude(Filter filter) {
return only((n, v) -> !filter.test(n, v));
}
public Builder exclude(Predicate<String> nameFilter) {
return only(nameFilter.negate());
}
public Builder exclude(String... names) {
Set<String> excluded = new HashSet<>();
for (String name : names) {
excluded.add(name);
}
return exclude(excluded::contains);
}
public Builder excludeRegex(String... nameRegexes) {
List<Predicate<String>> tests = new ArrayList<>();
for (String regex : nameRegexes) {
tests.add(Pattern.compile(regex).asPredicate());
}
return only((n, v) -> {
for (Predicate<String> test : tests) {
if (test.test(n)) {
return false;
}
}
return true;
});
}
public Builder extra(String... names) {
for (String name : names) {
extra.add(name);
}
return this;
}
public Builder rename(Function<String, String> renamer) {
apply(s -> {
s.name = renamer.apply(s.name);
});
return this;
}
public Builder stripPrefix(String prefix) {
return apply(s -> {
if (s.name.startsWith(prefix)) {
s.name = s.name.substring(prefix.length());
} else if (extra.contains(s.name)) {
return;
} else {
s.drop();
}
});
}
public IntConstantsMap scan() {
return build(true);
}
public IntConstantsMap scanAll() {
return build(false);
}
private IntConstantsMap build(boolean onlyPublic) {
Map<Integer, String> namesByValue = new HashMap<>();
Map<String, Integer> valuesByName = new HashMap<>();
BiConsumer<String, Integer> putter = (name, value) -> {
if (namesByValue.containsKey(value)) {
throw newDuplicateException("value", value, name, namesByValue.get(value));
}
if (valuesByName.containsKey(name)) {
throw newDuplicateException("name", name, value, valuesByName.get(name));
}
namesByValue.put(value, name);
valuesByName.put(name, value);
};
try {
for (Field field : source.getDeclaredFields()) {
processField(field, putter, onlyPublic);
}
} catch (IllegalAccessException e) {
throw new ConstantsMapException(e);
}
return new IntConstantsMap(
Collections.unmodifiableMap(namesByValue),
Collections.unmodifiableMap(valuesByName)
);
}
private void processField(Field field, BiConsumer<String, Integer> putter, boolean onlyPublic)
throws IllegalAccessException {
if (!Modifier.isStatic(field.getModifiers())) {
return;
}
if (!Modifier.isFinal(field.getModifiers())) {
return;
}
boolean clearAccessible = false;
if (!Modifier.isPublic(field.getModifiers())) {
if (onlyPublic) {
return;
} else if (!isAccessibleFlagSet(field)) {
field.setAccessible(true);
clearAccessible = true;
}
}
try {
ConstantSpec spec = new ConstantSpec();
spec.name = field.getName();
spec.value = field.getInt(null);
for (Consumer<ConstantSpec> t : transforms) {
t.accept(spec);
if (spec.name == null) {
return;
}
}
putter.accept(spec.name, spec.value);
} finally {
if (clearAccessible) {
field.setAccessible(false);
}
}
}
/*
* Yes, this method exists only so that neither Java 8 nor Java 9 complain about deprecation.
*/
@Deprecated
private boolean isAccessibleFlagSet(Field f) {
return f.isAccessible();
}
private ConstantsMapException newDuplicateException(String what, Object common, Object current, Object old) {
return new ConstantsMapException(
String.format(
"Duplicate %1$s: %2$s -> %3$s and %2$s -> %4$s",
what,
common,
current,
old
)
);
}
}
}

View File

@ -30,18 +30,8 @@ public class PrimitiveUtil {
private static final Map<Class<?>, Object> PRIMITIVE_TO_NULL = new HashMap<>();
static {
for (
Class<?> boxed : new Class<?>[] {
Boolean.class,
Byte.class,
Short.class,
Character.class,
Integer.class,
Long.class,
Float.class,
Double.class
}
) {
for (Class<?> boxed : new Class<?>[] { Boolean.class, Byte.class, Short.class, Character.class, Integer.class,
Long.class, Float.class, Double.class }) {
try {
PRIMITIVE_TO_BOXED.put((Class<?>) boxed.getField("TYPE").get(null), boxed);
} catch (Exception e) {

View File

@ -40,8 +40,7 @@ import java.util.stream.Stream;
/**
* Contains static methods to create {@link Stream Streams} that synchronize
* their
* <a href=
* their <a href=
* "https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps">
* terminal operations</a> on a given monitor.
*
@ -1070,21 +1069,18 @@ public class SyncStreams {
}
/**
* Wraps the given {@link Stream} to make all
* <a href=
* Wraps the given {@link Stream} to make all <a href=
* "https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps">
* terminal operations</a> acquire the provided monitor's lock before
* execution. Intermediate operations
* return streams that are also synchronized on the same object. The created
* stream will behave identically
* to the provided stream in all other aspects. Use this to synchronize
* access to stream's source.
* execution. Intermediate operations return streams that are also
* synchronized on the same object. The created stream will behave
* identically to the provided stream in all other aspects. Use this to
* synchronize access to stream's source.
* <p>
* <i>The returned {@code Stream}'s {@link Stream#iterator() iterator()} and
* {@link Stream#spliterator()
* spliterator()} methods return regular non-synchronized iterators and
* spliterators respectively</i>. It
* is the user's responsibility to avoid concurrency issues:
* {@link Stream#spliterator() spliterator()} methods return regular
* non-synchronized iterators and spliterators respectively</i>. It is the
* user's responsibility to avoid concurrency issues:
*
* <pre>
* synchronized (stream.getMonitor()) {
@ -1103,14 +1099,17 @@ public class SyncStreams {
* stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
* </pre>
*
* @param <T> the class of objects in the Stream
* @param stream the stream to wrap.
* @param monitor the object that the stream will use for synchronization.
* When {@code null}, the stream
* will synchronize on itself.
* @param <T>
* the class of objects in the Stream
* @param stream
* the stream to wrap.
* @param monitor
* the object that the stream will use for synchronization. When
* {@code null}, the stream will synchronize on itself.
* @return a {@link SyncStream SyncStream&lt;T&gt;} synchronized on
* {@code monitor} and backed by {@code stream}.
* @throws NullPointerException if {@code stream == null}.
* @throws NullPointerException
* if {@code stream == null}.
*/
public static <T> SyncStream<T> synchronizedStream(Stream<T> stream, Object monitor) {
Objects.requireNonNull(stream, "stream cannot be null");
@ -1118,22 +1117,19 @@ public class SyncStreams {
}
/**
* Wraps the given {@link IntStream} to make all
* <a href=
* Wraps the given {@link IntStream} to make all <a href=
* "https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps">
* terminal operations</a> acquire the provided monitor's lock before
* execution. Intermediate operations
* return streams that are also synchronized on the same object. The created
* stream will behave identically
* to the provided stream in all other aspects. Use this to synchronize
* access to stream's source.
* execution. Intermediate operations return streams that are also
* synchronized on the same object. The created stream will behave
* identically to the provided stream in all other aspects. Use this to
* synchronize access to stream's source.
* <p>
* <i>The returned {@code IntStream}'s {@link IntStream#iterator()
* iterator()} and
* {@link IntStream#spliterator() spliterator()} methods return regular
* non-synchronized iterators and
* spliterators respectively</i>. It is the user's responsibility to avoid
* concurrency issues:
* iterator()} and {@link IntStream#spliterator() spliterator()} methods
* return regular non-synchronized iterators and spliterators
* respectively</i>. It is the user's responsibility to avoid concurrency
* issues:
*
* <pre>
* synchronized (stream.getMonitor()) {
@ -1152,13 +1148,15 @@ public class SyncStreams {
* stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
* </pre>
*
* @param stream the stream to wrap.
* @param monitor the object that the stream will use for synchronization.
* When {@code null}, the stream
* will synchronize on itself.
* @param stream
* the stream to wrap.
* @param monitor
* the object that the stream will use for synchronization. When
* {@code null}, the stream will synchronize on itself.
* @return a {@link SyncIntStream} synchronized on {@code monitor} and
* backed by {@code stream}.
* @throws NullPointerException if {@code stream == null}.
* @throws NullPointerException
* if {@code stream == null}.
*/
public static SyncIntStream synchronizedStream(IntStream stream, Object monitor) {
Objects.requireNonNull(stream, "stream cannot be null");
@ -1166,22 +1164,19 @@ public class SyncStreams {
}
/**
* Wraps the given {@link LongStream} to make all
* <a href=
* Wraps the given {@link LongStream} to make all <a href=
* "https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps">
* terminal operations</a> acquire the provided monitor's lock before
* execution. Intermediate operations
* return streams that are also synchronized on the same object. The created
* stream will behave identically
* to the provided stream in all other aspects. Use this to synchronize
* access to stream's source.
* execution. Intermediate operations return streams that are also
* synchronized on the same object. The created stream will behave
* identically to the provided stream in all other aspects. Use this to
* synchronize access to stream's source.
* <p>
* <i>The returned {@code LongStream}'s {@link LongStream#iterator()
* iterator()} and
* {@link LongStream#spliterator() spliterator()} methods return regular
* non-synchronized iterators and
* spliterators respectively</i>. It is the user's responsibility to avoid
* concurrency issues:
* iterator()} and {@link LongStream#spliterator() spliterator()} methods
* return regular non-synchronized iterators and spliterators
* respectively</i>. It is the user's responsibility to avoid concurrency
* issues:
*
* <pre>
* synchronized (stream.getMonitor()) {
@ -1200,13 +1195,15 @@ public class SyncStreams {
* stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
* </pre>
*
* @param stream the stream to wrap.
* @param monitor the object that the stream will use for synchronization.
* When {@code null}, the stream
* will synchronize on itself.
* @param stream
* the stream to wrap.
* @param monitor
* the object that the stream will use for synchronization. When
* {@code null}, the stream will synchronize on itself.
* @return a {@link SyncLongStream} synchronized on {@code monitor} and
* backed by {@code stream}.
* @throws NullPointerException if {@code stream == null}.
* @throws NullPointerException
* if {@code stream == null}.
*/
public static SyncLongStream synchronizedStream(LongStream stream, Object monitor) {
Objects.requireNonNull(stream, "stream cannot be null");
@ -1214,22 +1211,19 @@ public class SyncStreams {
}
/**
* Wraps the given {@link DoubleStream} to make all
* <a href=
* Wraps the given {@link DoubleStream} to make all <a href=
* "https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps">
* terminal operations</a> acquire the provided monitor's lock before
* execution. Intermediate operations
* return streams that are also synchronized on the same object. The created
* stream will behave identically
* to the provided stream in all other aspects. Use this to synchronize
* access to stream's source.
* execution. Intermediate operations return streams that are also
* synchronized on the same object. The created stream will behave
* identically to the provided stream in all other aspects. Use this to
* synchronize access to stream's source.
* <p>
* <i>The returned {@code DoubleStream}'s {@link DoubleStream#iterator()
* iterator()} and
* {@link DoubleStream#spliterator() spliterator()} methods return regular
* non-synchronized iterators and
* spliterators respectively</i>. It is the user's responsibility to avoid
* concurrency issues:
* iterator()} and {@link DoubleStream#spliterator() spliterator()} methods
* return regular non-synchronized iterators and spliterators
* respectively</i>. It is the user's responsibility to avoid concurrency
* issues:
*
* <pre>
* synchronized (stream.getMonitor()) {
@ -1248,13 +1242,15 @@ public class SyncStreams {
* stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
* </pre>
*
* @param stream the stream to wrap.
* @param monitor the object that the stream will use for synchronization.
* When {@code null}, the stream
* will synchronize on itself.
* @param stream
* the stream to wrap.
* @param monitor
* the object that the stream will use for synchronization. When
* {@code null}, the stream will synchronize on itself.
* @return a {@link SyncDoubleStream} synchronized on {@code monitor} and
* backed by {@code stream}.
* @throws NullPointerException if {@code stream == null}.
* @throws NullPointerException
* if {@code stream == null}.
*/
public static SyncDoubleStream synchronizedStream(DoubleStream stream, Object monitor) {
Objects.requireNonNull(stream, "stream cannot be null");

View File

@ -108,7 +108,7 @@ public class CharArrayIterator implements CharacterIterator {
return pos;
}
// @SuppressWarnings("all") Just STFU, this _is_ terrific
// @SuppressWarnings("all") Just STFU, this _is_ terrific
// SonarLint: "clone" should not be overridden (java:S2975)
// And I wouldn't have done that if only CharacterIterator had not required

View File

@ -103,14 +103,8 @@ public class Escaper {
}
public static final Escaper JAVA = new Escaper(
'\\',
'u',
"tbnrf'\"".toCharArray(),
"\t\b\n\r\f\'\"".toCharArray(),
true,
true
);
public static final Escaper JAVA = new Escaper('\\', 'u', "tbnrf'\"".toCharArray(), "\t\b\n\r\f\'\"".toCharArray(),
true, true);
private final char escapeChar;
private final char unicodeEscapeChar;
@ -120,14 +114,8 @@ public class Escaper {
private final boolean preferUnicode;
private final boolean strict;
protected Escaper(
char escapeChar,
char unicodeEscapeChar,
char[] safes,
char[] unsafes,
boolean preferUnicode,
boolean strict
) {
protected Escaper(char escapeChar, char unicodeEscapeChar, char[] safes, char[] unsafes, boolean preferUnicode,
boolean strict) {
this.escapeChar = escapeChar;
this.unicodeEscapeChar = unicodeEscapeChar;
this.safes = safes;
@ -152,8 +140,7 @@ public class Escaper {
for (char c : unsafes) {
if (c == escapeChar)
throw new IllegalArgumentException(
"Unsafe characters contain escape chatacter (escape character is escaped automatically)"
);
"Unsafe characters contain escape chatacter (escape character is escaped automatically)");
if (c == unicodeEscapeChar)
throw new IllegalArgumentException("Unsafe characters contain Unicode escape chatacter");
}
@ -173,11 +160,7 @@ public class Escaper {
end = Integer.MAX_VALUE;
else
end = src.getPosition() + length;
while (
src.has() &&
src.getPosition() < end &&
(until == null || !until.test(src.current()))
)
while (src.has() && src.getPosition() < end && (until == null || !until.test(src.current())))
escape(src.consume(), output);
}
@ -225,11 +208,7 @@ public class Escaper {
int result = 0;
while (
src.has() &&
src.getPosition() < end &&
(until == null || !until.test(src.current()))
) {
while (src.has() && src.getPosition() < end && (until == null || !until.test(src.current()))) {
result += getEscapedLength(src.consume());
}
@ -257,11 +236,7 @@ public class Escaper {
end = Integer.MAX_VALUE;
else
end = src.getPosition() + length;
while (
src.has() &&
src.getPosition() < end &&
(until == null || !until.test(src.current()))
) {
while (src.has() && src.getPosition() < end && (until == null || !until.test(src.current()))) {
output.accept(unescapeOneSequence(src));
}
}
@ -282,10 +257,8 @@ public class Escaper {
if (src.current() == unicodeEscapeChar) {
src.next();
return (char) (hexValue(src.consume()) << (4 * 3) |
hexValue(src.consume()) << (4 * 2) |
hexValue(src.consume()) << (4 * 1) |
hexValue(src.consume()) << (4 * 0));
return (char) (hexValue(src.consume()) << (4 * 3) | hexValue(src.consume()) << (4 * 2)
| hexValue(src.consume()) << (4 * 1) | hexValue(src.consume()) << (4 * 0));
}
int index = ArrayUtil.firstIndexOf(safes, src.current());
@ -315,11 +288,7 @@ public class Escaper {
int result = 0;
while (
src.has() &&
src.getPosition() < end &&
(until == null || !until.test(src.current()))
) {
while (src.has() && src.getPosition() < end && (until == null || !until.test(src.current()))) {
skipOneSequence(src);
result++;
}
@ -328,11 +297,7 @@ public class Escaper {
}
public void skipOneSequence(CharReader src) {
if (
src.current() == escapeChar
&&
src.next() == unicodeEscapeChar
) {
if (src.current() == escapeChar && src.next() == unicodeEscapeChar) {
src.advance(4);
}
src.next();

View File

@ -86,7 +86,7 @@ public class FancyCharacterIterator implements CharacterIterator {
return sb.toString();
}
// @SuppressWarnings("all") Just STFU, this _is_ terrific
// @SuppressWarnings("all") Just STFU, this _is_ terrific
// SonarLint: "clone" should not be overridden (java:S2975)
// And I wouldn't have done that if only CharacterIterator had not required

View File

@ -41,13 +41,8 @@ public class StringUtil {
private static final String EMPTY_PLACEHOLDER = "[empty]";
private static final String DEFAULT_SEPARATOR = "; ";
public static <T> String arrayToString(
T[] array,
String separator,
String empty,
String nullPlaceholder,
String nullArray
) {
public static <T> String arrayToString(T[] array, String separator, String empty, String nullPlaceholder,
String nullArray) {
if (separator == null) {
throw new IllegalArgumentException(new NullPointerException());
@ -79,13 +74,8 @@ public class StringUtil {
return arrayToString(array, DEFAULT_SEPARATOR);
}
public static String iteratorToString(
Iterator<?> iterator,
String separator,
String empty,
String nullPlaceholder,
String nullIterator
) {
public static String iteratorToString(Iterator<?> iterator, String separator, String empty, String nullPlaceholder,
String nullIterator) {
if (separator == null) {
throw new IllegalArgumentException(new NullPointerException());
@ -119,13 +109,8 @@ public class StringUtil {
return iteratorToString(iterator, DEFAULT_SEPARATOR);
}
public static String iterableToString(
Iterable<?> iterable,
String separator,
String empty,
String nullPlaceholder,
String nullIterable
) {
public static String iterableToString(Iterable<?> iterable, String separator, String empty, String nullPlaceholder,
String nullIterable) {
if (separator == null) {
throw new IllegalArgumentException(new NullPointerException());
@ -146,14 +131,8 @@ public class StringUtil {
return iterableToString(iterable, DEFAULT_SEPARATOR);
}
public static <T> String supplierToString(
IntFunction<T> supplier,
int length,
String separator,
String empty,
String nullPlaceholder,
String nullSupplier
) {
public static <T> String supplierToString(IntFunction<T> supplier, int length, String separator, String empty,
String nullPlaceholder, String nullSupplier) {
if (separator == null)
throw new IllegalArgumentException(new NullPointerException());
@ -163,28 +142,15 @@ public class StringUtil {
return empty;
if (length > 0) {
return supplierToStringExactly(
supplier,
length,
separator,
nullPlaceholder
);
return supplierToStringExactly(supplier, length, separator, nullPlaceholder);
} else {
return supplierToStringUntilNull(
supplier,
separator,
empty
);
return supplierToStringUntilNull(supplier, separator, empty);
}
}
private static <T> String supplierToStringExactly(
IntFunction<T> supplier,
int length,
String separator,
String nullPlaceholder
) {
private static <T> String supplierToStringExactly(IntFunction<T> supplier, int length, String separator,
String nullPlaceholder) {
T element = supplier.apply(0);
StringBuilder sb = new StringBuilder(element == null ? nullPlaceholder : element.toString());
@ -198,11 +164,7 @@ public class StringUtil {
return sb.toString();
}
private static <T> String supplierToStringUntilNull(
IntFunction<T> supplier,
String separator,
String empty
) {
private static <T> String supplierToStringUntilNull(IntFunction<T> supplier, String separator, String empty) {
T element = supplier.apply(0);
if (element == null) {
@ -366,11 +328,7 @@ public class StringUtil {
StringBuilder sb = new StringBuilder();
charLoop: for (char c : src.toCharArray()) {
if (
(resultIndex + 1) < arrayLength
&&
test.test(c)
) {
if ((resultIndex + 1) < arrayLength && test.test(c)) {
result[resultIndex] = resetStringBuilder(sb);
++resultIndex;
continue charLoop;
@ -389,17 +347,17 @@ public class StringUtil {
* index.
* <p>
* Indices {@code 0} and {@code src.length() - 1} produce {@code str}
* excluding
* the specified character and {@code ""}.
* excluding the specified character and {@code ""}.
* <p>
*
* @param src the String to split
* @param at index to split at
* @throws IllegalArgumentException if the index is out of bounds for
* {@code src}
* @param src
* the String to split
* @param at
* index to split at
* @throws IllegalArgumentException
* if the index is out of bounds for {@code src}
* @return an array containing the substrings, in order of encounter in
* {@code src}.
* Its length is always 2.
* {@code src}. Its length is always 2.
*/
public static String[] splitAt(String src, int at) {
Objects.requireNonNull(src, "src");
@ -416,10 +374,7 @@ public class StringUtil {
return new String[] { src.substring(0, src.length() - 1), "" };
}
return new String[] {
src.substring(0, at),
src.substring(at + 1)
};
return new String[] { src.substring(0, at), src.substring(at + 1) };
}
/**
@ -427,8 +382,7 @@ public class StringUtil {
* indices.
* <p>
* Indices {@code 0} and {@code src.length() - 1} produce extra zero-length
* outputs.
* Duplicate indices produce extra zero-length outputs.
* outputs. Duplicate indices produce extra zero-length outputs.
* <p>
* Examples:
*
@ -439,13 +393,14 @@ public class StringUtil {
* splitAt("a.b", 1, 1, 1) -> {"a", "", "", "b"}
* </pre>
*
* @param src the String to split
* @param at indices to split at, in any order
* @throws IllegalArgumentException if some index is out of bounds for
* {@code src}
* @param src
* the String to split
* @param at
* indices to split at, in any order
* @throws IllegalArgumentException
* if some index is out of bounds for {@code src}
* @return an array containing the substrings, in order of encounter in
* {@code src}.
* Its length is always {@code at.length + 1}.
* {@code src}. Its length is always {@code at.length + 1}.
*/
public static String[] splitAt(String src, int... at) {
Objects.requireNonNull(src, "src");
@ -553,10 +508,8 @@ public class StringUtil {
}
if (endPos < beginPos) {
throw new IllegalArgumentException(
"endPos must be greater than or equal to beginPos (endPos="
+ endPos + ", beginPos=" + beginPos + ")"
);
throw new IllegalArgumentException("endPos must be greater than or equal to beginPos (endPos=" + endPos
+ ", beginPos=" + beginPos + ")");
}
if (endPos >= Math.min(a.length, b.length)) {
@ -592,8 +545,7 @@ public class StringUtil {
/**
* Finds and returns the index of the specified appearance of the specified
* character
* in the given array. The search starts at index 0.
* character in the given array. The search starts at index 0.
* <p>
* Examples:
* <p>
@ -630,10 +582,12 @@ public class StringUtil {
* </tr>
* </table>
*
* @param src - the array to search in.
* @param target - the character to search for.
* @param skip - the amount of <code>target</code> characters to be
* skipped.
* @param src
* - the array to search in.
* @param target
* - the character to search for.
* @param skip
* - the amount of <code>target</code> characters to be skipped.
* @return The index of the <code>skip+1</code>th <code>target</code>
* character or -1, if none found.
* @see StringUtil#indexFromEnd(char[], char, int)
@ -653,8 +607,7 @@ public class StringUtil {
/**
* Finds and returns the index of the specified appearance of the specified
* character
* in the given array. The search starts at index
* character in the given array. The search starts at index
* <code>src.length - 1</code>.
* <p>
* Examples:
@ -692,13 +645,15 @@ public class StringUtil {
* </tr>
* </table>
*
* @param src - the array to search in.
* @param target - the character to search for.
* @param skip - the amount of <code>target</code> characters to be
* skipped.
* @param src
* - the array to search in.
* @param target
* - the character to search for.
* @param skip
* - the amount of <code>target</code> characters to be skipped.
* @return The index of the <code>skip+1</code>th
* <code>target</code>character
* from the end of the array or -1, if none found.
* <code>target</code>character from the end of the array or -1, if
* none found.
* @see StringUtil#indexFromBeginning(char[], char, int)
*/
public static int indexFromEnd(char[] src, char target, int skip) {
@ -873,12 +828,8 @@ public class StringUtil {
return result;
}
private static void buildCombinations(
StringBuilder sb,
Collection<String> result,
Iterable<String>[] parts,
int index
) {
private static void buildCombinations(StringBuilder sb, Collection<String> result, Iterable<String>[] parts,
int index) {
if (index >= parts.length) {
result.add(sb.toString());
} else {
@ -904,13 +855,8 @@ public class StringUtil {
return result;
}
private static void buildCombinations(
StringBuilder sb,
String[] result,
int[] resultIndex,
String[][] parts,
int index
) {
private static void buildCombinations(StringBuilder sb, String[] result, int[] resultIndex, String[][] parts,
int index) {
if (index >= parts.length) {
result[resultIndex[0]++] = sb.toString();
} else {
@ -985,10 +931,7 @@ public class StringUtil {
}
private static char hexDigit(long value, int digit) {
return hexDigit(
(int) (value >>> (4 * digit))
& 0xF
);
return hexDigit((int) (value >>> (4 * digit)) & 0xF);
}
public static char hexDigit(int value) {

View File

@ -27,10 +27,9 @@ public abstract class AbstractCharReader implements CharReader {
/**
* Current position of this CharReader. The reader maps its input to
* positions starting from 0.
* Positions that are negative or lower than 0 are invalid.
* {@link #current()}
* will throw an exception if position is invalid.
* positions starting from 0. Positions that are negative or lower than 0
* are invalid. {@link #current()} will throw an exception if position is
* invalid.
*/
protected int position = 0;

View File

@ -51,9 +51,12 @@ public abstract class BufferedCharReader extends AbstractCharReader {
/**
* Acquires next characters and stores them in the array.
*
* @param buffer the output array
* @param offset index of the first character
* @param length maximum amount of characters to be pulled
* @param buffer
* the output array
* @param offset
* index of the first character
* @param length
* maximum amount of characters to be pulled
* @return the amount of characters actually pulled
*/
protected int pullChars(char[] buffer, int offset, int length) {

View File

@ -179,8 +179,7 @@ public interface CharReader {
/**
* Skips to the end of the current line. Both <code>"\n"</code>,
* <code>"\r"</code>
* and <code>"\r\n"</code> are considered line separators.
* <code>"\r"</code> and <code>"\r\n"</code> are considered line separators.
*
* @return the amount of characters in the skipped line
*/

View File

@ -38,8 +38,7 @@ public class StringCharReader extends AbstractCharReader {
int end = offset + length;
if (end > str.length() || offset < 0)
throw new IllegalArgumentException(
"String contains [0; " + str.length() + "), requested [" + offset + "; " + end + ")"
);
"String contains [0; " + str.length() + "), requested [" + offset + "; " + end + ")");
this.offset = offset;
this.length = length;

View File

@ -45,8 +45,15 @@ public interface ThrowingBiConsumer<T, U, E extends Exception> {
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(
ThrowingBiConsumer<? super T, ? super U, ? extends E> first,
ThrowingBiConsumer<? super T, ? super U, ? extends E> second
) {
ThrowingBiConsumer<? super T, ? super U, ? extends E> second) {
return (t, u) -> {
first.accept(t, u);
second.accept(t, u);
};
}
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(BiConsumer<? super T, ? super U> first,
ThrowingBiConsumer<? super T, ? super U, E> second) {
return (t, u) -> {
first.accept(t, u);
second.accept(t, u);
@ -54,19 +61,7 @@ public interface ThrowingBiConsumer<T, U, E extends Exception> {
}
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(
BiConsumer<? super T, ? super U> first,
ThrowingBiConsumer<? super T, ? super U, E> second
) {
return (t, u) -> {
first.accept(t, u);
second.accept(t, u);
};
}
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(
ThrowingBiConsumer<? super T, ? super U, E> first,
BiConsumer<? super T, ? super U> second
) {
ThrowingBiConsumer<? super T, ? super U, E> first, BiConsumer<? super T, ? super U> second) {
return (t, u) -> {
first.accept(t, u);
second.accept(t, u);

View File

@ -39,30 +39,24 @@ public interface ThrowingConsumer<T, E extends Exception> {
};
}
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(
ThrowingConsumer<? super T, ? extends E> first,
ThrowingConsumer<? super T, ? extends E> second
) {
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(ThrowingConsumer<? super T, ? extends E> first,
ThrowingConsumer<? super T, ? extends E> second) {
return t -> {
first.accept(t);
second.accept(t);
};
}
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(
Consumer<? super T> first,
ThrowingConsumer<? super T, ? extends E> second
) {
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(Consumer<? super T> first,
ThrowingConsumer<? super T, ? extends E> second) {
return t -> {
first.accept(t);
second.accept(t);
};
}
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(
ThrowingConsumer<? super T, ? extends E> first,
Consumer<? super T> second
) {
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(ThrowingConsumer<? super T, ? extends E> first,
Consumer<? super T> second) {
return t -> {
first.accept(t);
second.accept(t);

View File

@ -28,10 +28,8 @@ public interface ThrowingFunction<T, R, E extends Exception> {
R apply(T t) throws E;
@SuppressWarnings("unchecked")
default Function<T, R> withHandler(
BiConsumer<? super T, ? super E> handler,
Function<? super T, ? extends R> value
) {
default Function<T, R> withHandler(BiConsumer<? super T, ? super E> handler,
Function<? super T, ? extends R> value) {
return t -> {
try {
return apply(t);
@ -59,22 +57,17 @@ public interface ThrowingFunction<T, R, E extends Exception> {
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(
ThrowingFunction<? super T, I, ? extends E> first,
ThrowingFunction<? super I, ? extends R, ? extends E> second
) {
ThrowingFunction<? super I, ? extends R, ? extends E> second) {
return t -> second.apply(first.apply(t));
}
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(Function<? super T, I> first,
ThrowingFunction<? super I, ? extends R, E> second) {
return t -> second.apply(first.apply(t));
}
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(
Function<? super T, I> first,
ThrowingFunction<? super I, ? extends R, E> second
) {
return t -> second.apply(first.apply(t));
}
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(
ThrowingFunction<? super T, I, E> first,
Function<? super I, ? extends R> second
) {
ThrowingFunction<? super T, I, E> first, Function<? super I, ? extends R> second) {
return t -> second.apply(first.apply(t));
}

View File

@ -38,10 +38,8 @@ public interface ThrowingRunnable<E extends Exception> {
};
}
public static <E extends Exception> ThrowingRunnable<E> concat(
ThrowingRunnable<? extends E> first,
ThrowingRunnable<? extends E> second
) {
public static <E extends Exception> ThrowingRunnable<E> concat(ThrowingRunnable<? extends E> first,
ThrowingRunnable<? extends E> second) {
return () -> {
first.run();
second.run();

View File

@ -49,10 +49,8 @@ public class RangeIterator<E> implements Iterator<E> {
public E next() {
update();
if (nextIndex >= from + amount) {
throw new NoSuchElementException(
"RangeIterator about to retrieve element " + nextIndex
+ " which exceeds upper boundary " + (from + amount)
);
throw new NoSuchElementException("RangeIterator about to retrieve element " + nextIndex
+ " which exceeds upper boundary " + (from + amount));
}
E result = parent.next();

View File

@ -18,177 +18,6 @@
package ru.windcorp.progressia;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import org.apache.logging.log4j.LogManager;
import ru.windcorp.progressia.common.util.crash.CrashReports;
/**
* A class providing access to build metadata.
*/
public class Progressia {
private static final String NAME = "Progressia";
private static String version;
private static String gitCommit;
private static String gitBranch;
private static String buildId;
static {
try {
Manifest manifest = findManifest();
if (manifest == null) {
setDevelopmentMetadata();
LogManager.getLogger().info(
"Manifest with Specification-Title not found. "
+ "Either you are in a development environment or something has gone horribly wrong with classloaders."
);
} else {
fillMetadata(manifest);
}
} catch (Throwable t) {
CrashReports.crash(t, "Something went wrong while loading metadata");
}
}
private static Manifest findManifest() {
try {
Enumeration<URL> resources = Progressia.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
Collection<IOException> exceptions = new ArrayList<>();
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
try {
Manifest manifest = new Manifest(url.openStream());
Attributes mainAttributes = manifest.getMainAttributes();
if (NAME.equals(mainAttributes.getValue("Specification-Title"))) {
return manifest;
}
} catch (IOException e) {
exceptions.add(e);
}
}
if (exceptions.isEmpty()) {
return null;
}
IOException scapegoat = null;
for (IOException e : exceptions) {
if (scapegoat == null) {
scapegoat = e;
} else {
scapegoat.addSuppressed(e);
}
}
throw CrashReports.report(scapegoat, "Could not read manifest");
} catch (IOException e) {
throw CrashReports.report(e, "Could not read manifest");
}
}
private static void setDevelopmentMetadata() {
version = "dev";
gitCommit = "-";
gitBranch = "-";
buildId = "-";
}
private static void fillMetadata(Manifest manifest) {
version = getAttributeOrCrash(manifest, "Implementation-Version");
gitCommit = getAttributeOrCrash(manifest, "Implementation-Version-Git-Commit");
gitBranch = getAttributeOrCrash(manifest, "Implementation-Version-Git-Branch");
buildId = getAttributeOrCrash(manifest, "Implementation-Version-BuildId");
}
private static String getAttributeOrCrash(Manifest manifest, String key) {
String result = manifest.getMainAttributes().getValue(key);
if (result == null) {
throw CrashReports.report(null, "Manifest exists but attribute " + key + " not found");
}
return result;
}
public static String getName() {
return NAME;
}
/**
* Returns the version of the game as a String. Version data is retrieved
* from a {@code META-INF/MANIFEST.MF} file located in the main JAR. Version
* format depends on way the game was built:
* <ul>
* <li><code>dev</code> if no matching manifest was found, e.g. when launching from an IDE</li>
* <li>The value of <code>Implementation-Version</code> specified in the manifest:
* <ul>
* <li>[Stage-]Major.Minor.Patch, e.g. <code>alpha-0.3.2</code> or <code>1.4.2</code>, for released versions</li>
* <li>BuildId, e.g. <code>WJ7</code>, for snapshots built by automation systems</li>
* <li>YYYY-MM-DD, e.g. <code>2021-12-32</code>, for snapshots built manually</li>
* </ul>
* </li>
* </ul>
*
* @return the version
*/
public static String getVersion() {
return version;
}
public static String getFullerVersion() {
if (isDefaultGitBranch() || "-".equals(gitBranch)) {
return version;
} else {
return String.format("%s/%s", version, gitBranch);
}
}
/**
* @return the buildId or <code>"-"</code>
*/
public static String getBuildId() {
return buildId;
}
/**
* @return the Git commit or <code>"-"</code>
*/
public static String getGitCommit() {
return gitCommit;
}
public static String getGitCommitShort() {
if (gitCommit == null || "-".equals(gitCommit)) {
return gitCommit;
}
return gitCommit.substring(0, Math.min(7, gitCommit.length()));
}
/**
* @return the Git branch or <code>"-"</code>
*/
public static String getGitBranch() {
return gitBranch;
}
public static boolean isDefaultGitBranch() {
return "master".equals(gitBranch) || "main".equals(gitBranch);
}
public static String getFullVersion() {
return String.format("%s/%s/%s/%s", version, gitBranch, getGitCommitShort(), buildId);
}
}

View File

@ -18,37 +18,22 @@
package ru.windcorp.progressia;
import org.apache.logging.log4j.LogManager;
import ru.windcorp.progressia.client.graphics.GUI;
import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.common.util.crash.analyzers.OutOfMemoryAnalyzer;
import ru.windcorp.progressia.common.util.crash.providers.*;
import ru.windcorp.progressia.test.LayerTitle;
public class ProgressiaLauncher {
public static String[] arguments;
private static Proxy proxy;
public static void launch(String[] args, Proxy proxy) {
arguments = args.clone();
setupCrashReports();
LogManager.getRootLogger().info("Launching " + Progressia.getName() + " version " + Progressia.getFullVersion());
proxy.initialize();
ProgressiaLauncher.proxy = proxy;
GUI.addTopLayer(new LayerTitle("Title"));
}
public static Proxy getProxy() {
return proxy;
}
private static void setupCrashReports() {
// Context providers
CrashReports.registerProvider(new VersionProvider());
CrashReports.registerProvider(new OSContextProvider());
CrashReports.registerProvider(new RAMContextProvider());
CrashReports.registerProvider(new JavaVersionContextProvider());

View File

@ -69,11 +69,7 @@ public class Client {
return;
}
getCamera().setAnchor(
new EntityAnchor(
getWorld().getEntityRenderable(entity)
)
);
getCamera().setAnchor(new EntityAnchor(getWorld().getEntityRenderable(entity)));
}
}

View File

@ -25,12 +25,12 @@ import ru.windcorp.progressia.client.graphics.backend.RenderTaskQueue;
import ru.windcorp.progressia.client.graphics.flat.FlatRenderProgram;
import ru.windcorp.progressia.client.graphics.font.GNUUnifontLoader;
import ru.windcorp.progressia.client.graphics.font.Typefaces;
import ru.windcorp.progressia.client.graphics.gui.ColorScheme;
import ru.windcorp.progressia.client.graphics.texture.Atlases;
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
import ru.windcorp.progressia.client.localization.Localizer;
import ru.windcorp.progressia.common.resource.ResourceManager;
import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.server.ServerState;
import ru.windcorp.progressia.test.TestContent;
import ru.windcorp.progressia.test.TestMusicPlayer;
@ -38,21 +38,16 @@ public class ClientProxy implements Proxy {
@Override
public void initialize() {
GraphicsBackend.initialize();
try {
RenderTaskQueue.waitAndInvoke(FlatRenderProgram::init);
RenderTaskQueue.waitAndInvoke(WorldRenderProgram::init);
RenderTaskQueue.waitAndInvoke(
() -> Typefaces
.setDefault(GNUUnifontLoader.load(ResourceManager.getResource("assets/unifont-13.0.03.hex.gz")))
);
RenderTaskQueue.waitAndInvoke(() -> Typefaces
.setDefault(GNUUnifontLoader.load(ResourceManager.getResource("assets/unifont-13.0.03.hex.gz"))));
} catch (InterruptedException e) {
throw CrashReports.report(e, "ClientProxy failed");
}
ColorScheme.load(ResourceManager.getResource("assets/default.colorScheme"));
Localizer.getInstance().setLanguage("en-US");
TestContent.registerContent();
@ -61,6 +56,10 @@ public class ClientProxy implements Proxy {
AudioSystem.initialize();
ServerState.startServer();
ClientState.connectToLocalServer();
TestMusicPlayer.start();
}
}

View File

@ -20,13 +20,10 @@ package ru.windcorp.progressia.client;
import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel;
import ru.windcorp.progressia.client.graphics.GUI;
import ru.windcorp.progressia.client.graphics.Layer;
import ru.windcorp.progressia.client.graphics.world.LayerWorld;
import ru.windcorp.progressia.common.world.DefaultWorldData;
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
import ru.windcorp.progressia.server.ServerState;
import ru.windcorp.progressia.test.LayerAbout;
import ru.windcorp.progressia.test.LayerTestText;
import ru.windcorp.progressia.test.LayerTestUI;
import ru.windcorp.progressia.test.TestContent;
@ -46,48 +43,18 @@ public class ClientState {
DefaultWorldData world = new DefaultWorldData();
LocalServerCommsChannel channel = new LocalServerCommsChannel(
ServerState.getInstance()
);
LocalServerCommsChannel channel = new LocalServerCommsChannel(ServerState.getInstance());
Client client = new Client(world, channel);
channel.connect(TestContent.PLAYER_LOGIN);
setInstance(client);
displayLoadingScreen();
}
GUI.addBottomLayer(new LayerWorld(client));
GUI.addTopLayer(new LayerTestUI());
GUI.addTopLayer(new LayerAbout());
private static void displayLoadingScreen() {
GUI.addTopLayer(new LayerTestText("Text", new MutableStringLocalized("LayerText.Load"), layer -> {
Client client = ClientState.getInstance();
// TODO refacetor and remove
if (client != null) {
client.getComms().processPackets();
}
if (client != null && client.getLocalPlayer().hasEntity()) {
GUI.removeLayer(layer);
// TODO refactor, this shouldn't be here
LayerWorld layerWorld = new LayerWorld(client);
LayerTestUI layerUI = new LayerTestUI();
LayerAbout layerAbout = new LayerAbout();
GUI.addBottomLayer(layerWorld);
GUI.addTopLayer(layerUI);
GUI.addTopLayer(layerAbout);
}
}));
}
public static void disconnectFromLocalServer() {
getInstance().getComms().disconnect();
for (Layer layer : GUI.getLayers()) {
GUI.removeLayer(layer);
}
}
private ClientState() {

View File

@ -43,10 +43,7 @@ public class AudioManager {
private static Speaker musicSpeaker;
public static void initAL() {
String defaultDeviceName = alcGetString(
0,
ALC_DEFAULT_DEVICE_SPECIFIER
);
String defaultDeviceName = alcGetString(0, ALC_DEFAULT_DEVICE_SPECIFIER);
device = alcOpenDevice(defaultDeviceName);
@ -75,10 +72,7 @@ public class AudioManager {
lastSoundIndex = 0;
}
speaker = soundSpeakers.get(lastSoundIndex);
} while (
speaker.getState()
.equals(Speaker.State.PLAYING_LOOP)
);
} while (speaker.getState().equals(Speaker.State.PLAYING_LOOP));
return speaker;
}

View File

@ -29,10 +29,7 @@ public class AudioSystem {
}
static void loadAudioData() {
AudioManager.loadSound(
ResourceManager.getResource("assets/sounds/block_destroy_clap.ogg"),
"Progressia:BlockDestroy",
AudioFormat.MONO
);
AudioManager.loadSound(ResourceManager.getResource("assets/sounds/block_destroy_clap.ogg"),
"Progressia:BlockDestroy", AudioFormat.MONO);
}
}

View File

@ -22,10 +22,7 @@ import glm.vec._3.Vec3;
import ru.windcorp.progressia.client.audio.backend.SoundType;
import ru.windcorp.progressia.client.audio.backend.Speaker;
public class Music
extends Sound {
public class Music extends Sound {
public Music(SoundType soundType, int timeLength, float pitch, float gain) {
super(soundType, timeLength, new Vec3(), new Vec3(), pitch, gain);

View File

@ -40,14 +40,7 @@ public class Sound {
this(AudioRegistry.getInstance().get(id));
}
public Sound(
String id,
int timeLength,
Vec3 position,
Vec3 velocity,
float pitch,
float gain
) {
public Sound(String id, int timeLength, Vec3 position, Vec3 velocity, float pitch, float gain) {
this(id);
this.position = position;
this.velocity = velocity;
@ -55,14 +48,7 @@ public class Sound {
this.gain = gain;
}
public Sound(
SoundType soundType,
int timeLength,
Vec3 position,
Vec3 velocity,
float pitch,
float gain
) {
public Sound(SoundType soundType, int timeLength, Vec3 position, Vec3 velocity, float pitch, float gain) {
this(soundType);
this.position = position;
this.velocity = velocity;

View File

@ -39,12 +39,7 @@ public class AudioReader {
ShortBuffer rawAudio = decodeVorbis(resource, channelBuffer, rateBuffer);
return new SoundType(
id,
rawAudio,
format,
rateBuffer.get(0)
);
return new SoundType(id, rawAudio, format, rateBuffer.get(0));
}
public static SoundType readAsMono(Resource resource, String id) {
@ -55,15 +50,7 @@ public class AudioReader {
return readAsSpecified(resource, id, AL_FORMAT_STEREO16);
}
private static ShortBuffer decodeVorbis(
Resource dataToDecode,
IntBuffer channelsBuffer,
IntBuffer rateBuffer
) {
return stb_vorbis_decode_memory(
dataToDecode.readAsBytes(),
channelsBuffer,
rateBuffer
);
private static ShortBuffer decodeVorbis(Resource dataToDecode, IntBuffer channelsBuffer, IntBuffer rateBuffer) {
return stb_vorbis_decode_memory(dataToDecode.readAsBytes(), channelsBuffer, rateBuffer);
}
}

View File

@ -55,9 +55,8 @@ public class Listener {
if (isInWorld) {
if (wasInWorld) {
velocity.set(camera.getLastAnchorPosition()).sub(position).div(
(float) GraphicsInterface.getFrameLength()
);
velocity.set(camera.getLastAnchorPosition()).sub(position)
.div((float) GraphicsInterface.getFrameLength());
} else {
// If !wasInWorld, previous position is nonsence. Assume 0.
velocity.set(0);
@ -72,9 +71,9 @@ public class Listener {
}
/*
* Only apply if there is a chance that params changed.
* This can only happen if we are in world now (isInWorld) or we just
* left world (wasInWorld, then we need to reset).
* Only apply if there is a chance that params changed. This can only
* happen if we are in world now (isInWorld) or we just left world
* (wasInWorld, then we need to reset).
*/
if (isInWorld || wasInWorld) {
applyParams();
@ -91,17 +90,7 @@ public class Listener {
private void applyParams() {
alListener3f(AL_POSITION, position.x, position.y, position.z);
alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z);
alListenerfv(
AL_ORIENTATION,
new float[] {
oriAt.x,
oriAt.y,
oriAt.z,
oriUp.x,
oriUp.y,
oriUp.z
}
);
alListenerfv(AL_ORIENTATION, new float[] { oriAt.x, oriAt.y, oriAt.z, oriUp.x, oriUp.y, oriUp.z });
}
}

View File

@ -34,12 +34,7 @@ public class SoundType extends Namespaced {
private int audioBuffer;
private double duration;
public SoundType(
String id,
ShortBuffer rawAudio,
int format,
int sampleRate
) {
public SoundType(String id, ShortBuffer rawAudio, int format, int sampleRate) {
super(id);
this.rawAudio = rawAudio;
this.sampleRate = sampleRate;

View File

@ -24,9 +24,7 @@ import static org.lwjgl.openal.AL11.*;
public class Speaker {
public enum State {
NOT_PLAYING,
PLAYING,
PLAYING_LOOP
NOT_PLAYING, PLAYING, PLAYING_LOOP
}
// Buffers
@ -49,13 +47,7 @@ public class Speaker {
setAudioData(audioData);
}
public Speaker(
int audioData,
Vec3 position,
Vec3 velocity,
float pitch,
float gain
) {
public Speaker(int audioData, Vec3 position, Vec3 velocity, float pitch, float gain) {
setAudioData(audioData);
setPosition(position);
setVelocity(velocity);
@ -63,12 +55,7 @@ public class Speaker {
setGain(gain);
}
public Speaker(
Vec3 position,
Vec3 velocity,
float pitch,
float gain
) {
public Speaker(Vec3 position, Vec3 velocity, float pitch, float gain) {
setPosition(position);
setVelocity(velocity);
setPitch(pitch);

View File

@ -39,9 +39,7 @@ public class DefaultClientCommsListener implements CommsListener {
@Override
public void onPacketReceived(Packet packet) {
if (packet instanceof PacketAffectWorld) {
((PacketAffectWorld) packet).apply(
getClient().getWorld().getData()
);
((PacketAffectWorld) packet).apply(getClient().getWorld().getData());
} else if (packet instanceof PacketSetLocalPlayer) {
setLocalPlayer((PacketSetLocalPlayer) packet);
}

View File

@ -33,17 +33,12 @@ public class ControlTriggerLambda extends ControlTriggerInputBased {
private final Predicate<InputEvent> predicate;
private final BiConsumer<InputEvent, ControlData> dataWriter;
public ControlTriggerLambda(
String id,
Predicate<InputEvent> predicate,
BiConsumer<InputEvent, ControlData> dataWriter
) {
public ControlTriggerLambda(String id, Predicate<InputEvent> predicate,
BiConsumer<InputEvent, ControlData> dataWriter) {
super(id);
this.packetId = NamespacedUtil.getId(
NamespacedUtil.getNamespace(id),
"ControlKeyPress" + NamespacedUtil.getName(id)
);
this.packetId = NamespacedUtil.getId(NamespacedUtil.getNamespace(id),
"ControlKeyPress" + NamespacedUtil.getName(id));
this.predicate = predicate;
this.dataWriter = dataWriter;
@ -54,10 +49,7 @@ public class ControlTriggerLambda extends ControlTriggerInputBased {
if (!predicate.test(event))
return null;
PacketControl packet = new PacketControl(
packetId,
ControlDataRegistry.getInstance().create(getId())
);
PacketControl packet = new PacketControl(packetId, ControlDataRegistry.getInstance().create(getId()));
dataWriter.accept(event, packet.getControl());

View File

@ -29,11 +29,7 @@ public class ControlTriggerLocalLambda extends ControlTriggerInputBased {
private final Predicate<InputEvent> predicate;
private final Consumer<InputEvent> action;
public ControlTriggerLocalLambda(
String id,
Predicate<InputEvent> predicate,
Consumer<InputEvent> action
) {
public ControlTriggerLocalLambda(String id, Predicate<InputEvent> predicate, Consumer<InputEvent> action) {
super(id);
this.predicate = predicate;

View File

@ -27,216 +27,119 @@ import ru.windcorp.progressia.common.comms.controls.ControlData;
public class ControlTriggers {
public static ControlTriggerInputBased of(
String id,
BiConsumer<InputEvent, ControlData> dataWriter,
Predicate<InputEvent> predicate
) {
public static ControlTriggerInputBased of(String id, BiConsumer<InputEvent, ControlData> dataWriter,
Predicate<InputEvent> predicate) {
return new ControlTriggerLambda(id, predicate, dataWriter);
}
public static ControlTriggerInputBased of(
String id,
Consumer<ControlData> dataWriter,
Predicate<InputEvent> predicate
) {
return of(
id,
(input, control) -> dataWriter.accept(control),
predicate
);
public static ControlTriggerInputBased of(String id, Consumer<ControlData> dataWriter,
Predicate<InputEvent> predicate) {
return of(id, (input, control) -> dataWriter.accept(control), predicate);
}
public static ControlTriggerInputBased of(
String id,
Predicate<InputEvent> predicate
) {
return of(
id,
(input, control) -> {
},
predicate
);
public static ControlTriggerInputBased of(String id, Predicate<InputEvent> predicate) {
return of(id, (input, control) -> {
}, predicate);
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased of(
String id,
Class<I> inputType,
BiConsumer<I, ControlData> dataWriter,
Predicate<I>... predicates
) {
return of(
id,
createCheckedDataWriter(inputType, dataWriter),
createCheckedCompoundPredicate(inputType, predicates)
);
public static <I extends InputEvent> ControlTriggerInputBased of(String id, Class<I> inputType,
BiConsumer<I, ControlData> dataWriter, Predicate<I>... predicates) {
return of(id, createCheckedDataWriter(inputType, dataWriter),
createCheckedCompoundPredicate(inputType, predicates));
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased of(
String id,
Class<I> inputType,
Consumer<ControlData> dataWriter,
Predicate<I>... predicates
) {
return of(
id,
inputType,
(input, control) -> dataWriter.accept(control),
predicates
);
public static <I extends InputEvent> ControlTriggerInputBased of(String id, Class<I> inputType,
Consumer<ControlData> dataWriter, Predicate<I>... predicates) {
return of(id, inputType, (input, control) -> dataWriter.accept(control), predicates);
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased of(
String id,
Class<I> inputType,
Predicate<I>... predicates
) {
return of(
id,
(input, control) -> {
},
createCheckedCompoundPredicate(inputType, predicates)
);
public static <I extends InputEvent> ControlTriggerInputBased of(String id, Class<I> inputType,
Predicate<I>... predicates) {
return of(id, (input, control) -> {
}, createCheckedCompoundPredicate(inputType, predicates));
}
@SafeVarargs
public static ControlTriggerInputBased of(
String id,
BiConsumer<InputEvent, ControlData> dataWriter,
Predicate<InputEvent>... predicates
) {
return of(
id,
InputEvent.class,
dataWriter,
predicates
);
public static ControlTriggerInputBased of(String id, BiConsumer<InputEvent, ControlData> dataWriter,
Predicate<InputEvent>... predicates) {
return of(id, InputEvent.class, dataWriter, predicates);
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased of(
String id,
Consumer<ControlData> dataWriter,
Predicate<InputEvent>... predicates
) {
return of(
id,
(input, control) -> dataWriter.accept(control),
predicates
);
public static <I extends InputEvent> ControlTriggerInputBased of(String id, Consumer<ControlData> dataWriter,
Predicate<InputEvent>... predicates) {
return of(id, (input, control) -> dataWriter.accept(control), predicates);
}
@SafeVarargs
public static ControlTriggerInputBased of(
String id,
Predicate<InputEvent>... predicates
) {
return of(
id,
InputEvent.class,
(input, control) -> {
},
predicates
);
public static ControlTriggerInputBased of(String id, Predicate<InputEvent>... predicates) {
return of(id, InputEvent.class, (input, control) -> {
}, predicates);
}
public static ControlTriggerInputBased localOf(
String id,
Consumer<InputEvent> action,
Predicate<InputEvent> predicate
) {
//
//
///
///
//
//
//
//
//
//
//
//
//
public static ControlTriggerInputBased localOf(String id, Consumer<InputEvent> action,
Predicate<InputEvent> predicate) {
return new ControlTriggerLocalLambda(id, predicate, action);
}
public static ControlTriggerInputBased localOf(
String id,
Runnable action,
Predicate<InputEvent> predicate
) {
return localOf(
id,
input -> action.run(),
predicate
);
public static ControlTriggerInputBased localOf(String id, Runnable action, Predicate<InputEvent> predicate) {
return localOf(id, input -> action.run(), predicate);
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased localOf(
String id,
Class<I> inputType,
Consumer<I> action,
Predicate<I>... predicates
) {
return localOf(
id,
createCheckedAction(inputType, action),
createCheckedCompoundPredicate(inputType, predicates)
);
public static <I extends InputEvent> ControlTriggerInputBased localOf(String id, Class<I> inputType,
Consumer<I> action, Predicate<I>... predicates) {
return localOf(id, createCheckedAction(inputType, action),
createCheckedCompoundPredicate(inputType, predicates));
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased localOf(
String id,
Class<I> inputType,
Runnable action,
Predicate<I>... predicates
) {
return localOf(
id,
inputType,
input -> action.run(),
predicates
);
public static <I extends InputEvent> ControlTriggerInputBased localOf(String id, Class<I> inputType,
Runnable action, Predicate<I>... predicates) {
return localOf(id, inputType, input -> action.run(), predicates);
}
@SafeVarargs
public static ControlTriggerInputBased localOf(
String id,
Consumer<InputEvent> action,
Predicate<InputEvent>... predicates
) {
return localOf(
id,
InputEvent.class,
action,
predicates
);
public static ControlTriggerInputBased localOf(String id, Consumer<InputEvent> action,
Predicate<InputEvent>... predicates) {
return localOf(id, InputEvent.class, action, predicates);
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased localOf(
String id,
Runnable action,
Predicate<InputEvent>... predicates
) {
return of(
id,
input -> action.run(),
predicates
);
public static <I extends InputEvent> ControlTriggerInputBased localOf(String id, Runnable action,
Predicate<InputEvent>... predicates) {
return of(id, input -> action.run(), predicates);
}
private static <I extends InputEvent> BiConsumer<InputEvent, ControlData> createCheckedDataWriter(
Class<I> inputType,
BiConsumer<I, ControlData> dataWriter
) {
Class<I> inputType, BiConsumer<I, ControlData> dataWriter) {
return (inputEvent, control) -> dataWriter.accept(inputType.cast(inputEvent), control);
}
private static <I extends InputEvent> Consumer<InputEvent> createCheckedAction(
Class<I> inputType,
Consumer<I> action
) {
private static <I extends InputEvent> Consumer<InputEvent> createCheckedAction(Class<I> inputType,
Consumer<I> action) {
return inputEvent -> action.accept(inputType.cast(inputEvent));
}
private static <I extends InputEvent> Predicate<InputEvent> createCheckedCompoundPredicate(
Class<I> inputType,
Predicate<I>[] predicates
) {
private static <I extends InputEvent> Predicate<InputEvent> createCheckedCompoundPredicate(Class<I> inputType,
Predicate<I>[] predicates) {
return new CompoundCastPredicate<>(inputType, predicates);
}

View File

@ -19,7 +19,7 @@
package ru.windcorp.progressia.client.comms.controls;
import ru.windcorp.progressia.client.Client;
import ru.windcorp.progressia.client.graphics.input.InputEvent;
import ru.windcorp.progressia.client.graphics.input.bus.Input;
import ru.windcorp.progressia.common.comms.packets.Packet;
public class InputBasedControls {
@ -32,16 +32,15 @@ public class InputBasedControls {
this.client = client;
this.controls = ControlTriggerRegistry.getInstance().values().stream()
.filter(ControlTriggerInputBased.class::isInstance)
.toArray(ControlTriggerInputBased[]::new);
.filter(ControlTriggerInputBased.class::isInstance).toArray(ControlTriggerInputBased[]::new);
}
public void handleInput(InputEvent event) {
public void handleInput(Input input) {
for (ControlTriggerInputBased c : controls) {
Packet packet = c.onInputEvent(event);
Packet packet = c.onInputEvent(input.getEvent());
if (packet != null) {
event.consume();
input.consume();
client.getComms().sendPacket(packet);
break;
}

View File

@ -21,7 +21,6 @@ package ru.windcorp.progressia.client.comms.localhost;
import ru.windcorp.progressia.client.comms.ServerCommsChannel;
import ru.windcorp.progressia.common.comms.packets.Packet;
import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.ServerState;
public class LocalServerCommsChannel extends ServerCommsChannel {
@ -35,11 +34,7 @@ public class LocalServerCommsChannel extends ServerCommsChannel {
public void connect(String login) {
setState(State.CONNECTED);
this.localClient = new LocalClient(
server.getClientManager().grabClientId(),
login,
this
);
this.localClient = new LocalClient(server.getClientManager().grabClientId(), login, this);
server.getClientManager().addClient(localClient);
}
@ -55,7 +50,7 @@ public class LocalServerCommsChannel extends ServerCommsChannel {
@Override
public void disconnect() {
ServerState.getInstance().getClientManager().disconnectClient(localClient);
// Do nothing
}
}

View File

@ -34,7 +34,13 @@ public class Colors {
DEBUG_BLUE = toVector(0xFF0000FF),
DEBUG_CYAN = toVector(0xFF00FFFF),
DEBUG_MAGENTA = toVector(0xFFFF00FF),
DEBUG_YELLOW = toVector(0xFFFFFF00);
DEBUG_YELLOW = toVector(0xFFFFFF00),
LIGHT_GRAY = toVector(0xFFCBCBD0),
BLUE = toVector(0xFF37A2E6),
HOVER_BLUE = toVector(0xFFC3E4F7),
DISABLED_GRAY = toVector(0xFFE5E5E5),
DISABLED_BLUE = toVector(0xFFB2D8ED);
public static Vec4 toVector(int argb) {
return toVector(argb, new Vec4());

View File

@ -21,10 +21,16 @@ package ru.windcorp.progressia.client.graphics;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import com.google.common.eventbus.Subscribe;
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
import ru.windcorp.progressia.client.graphics.input.CursorEvent;
import ru.windcorp.progressia.client.graphics.input.FrameResizeEvent;
import ru.windcorp.progressia.client.graphics.input.InputEvent;
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
import ru.windcorp.progressia.client.graphics.input.WheelEvent;
import ru.windcorp.progressia.client.graphics.input.bus.Input;
public class GUI {
@ -39,11 +45,19 @@ public class GUI {
private static final List<LayerStackModification> MODIFICATION_QUEUE = Collections
.synchronizedList(new ArrayList<>());
private static class ModifiableInput extends Input {
@Override
public void initialize(InputEvent event, Target target) {
super.initialize(event, target);
}
}
private static final ModifiableInput THE_INPUT = new ModifiableInput();
private GUI() {
}
public static void addBottomLayer(Layer layer) {
Objects.requireNonNull(layer, "layer");
modify(layers -> {
layers.add(layer);
layer.onAdded();
@ -51,7 +65,6 @@ public class GUI {
}
public static void addTopLayer(Layer layer) {
Objects.requireNonNull(layer, "layer");
modify(layers -> {
layers.add(0, layer);
layer.onAdded();
@ -59,7 +72,6 @@ public class GUI {
}
public static void removeLayer(Layer layer) {
Objects.requireNonNull(layer, "layer");
modify(layers -> {
layers.remove(layer);
layer.onRemoved();
@ -110,12 +122,43 @@ public class GUI {
LAYERS.forEach(Layer::invalidate);
}
public static void dispatchInput(InputEvent event) {
synchronized (LAYERS) {
for (int i = 0; i < LAYERS.size(); ++i) {
LAYERS.get(i).handleInput(event);
private static void dispatchInputEvent(InputEvent event) {
Input.Target target;
if (event instanceof KeyEvent) {
if (((KeyEvent) event).isMouse()) {
target = Input.Target.HOVERED;
} else {
target = Input.Target.FOCUSED;
}
} else if (event instanceof CursorEvent) {
target = Input.Target.HOVERED;
} else if (event instanceof WheelEvent) {
target = Input.Target.HOVERED;
} else if (event instanceof FrameResizeEvent) {
return;
} else {
target = Input.Target.ALL;
}
THE_INPUT.initialize(event, target);
LAYERS.forEach(l -> l.handleInput(THE_INPUT));
}
public static Object getEventSubscriber() {
return new Object() {
@Subscribe
public void onFrameResized(FrameResizeEvent event) {
GUI.invalidateEverything();
}
@Subscribe
public void onInput(InputEvent event) {
dispatchInputEvent(event);
}
};
}
}

View File

@ -21,7 +21,7 @@ package ru.windcorp.progressia.client.graphics;
import java.util.concurrent.atomic.AtomicBoolean;
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
import ru.windcorp.progressia.client.graphics.input.InputEvent;
import ru.windcorp.progressia.client.graphics.input.bus.Input;
public abstract class Layer {
@ -106,7 +106,7 @@ public abstract class Layer {
protected abstract void doRender();
public abstract void handleInput(InputEvent input);
protected abstract void handleInput(Input input);
protected int getWidth() {
return GraphicsInterface.getFrameWidth();

View File

@ -1,56 +0,0 @@
/*
* Progressia
* Copyright (C) 2020-2022 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.graphics.backend;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import ru.windcorp.jputil.ConstantsMapException;
import ru.windcorp.jputil.IntConstantsMap;
import ru.windcorp.progressia.common.util.crash.CrashReports;
public class GLFWErrorHandler {
private static final IntConstantsMap ERROR_CODES;
static {
try {
ERROR_CODES = IntConstantsMap.from(GLFW.class)
.stripPrefix("GLFW_")
.onlyValued(i -> i >= 0x10000 && i <= 0x1FFFF)
.extra("GLFW_NO_ERROR")
.scan();
} catch (ConstantsMapException e) {
throw CrashReports.report(e, "Could not analyze GLFW error codes");
}
}
public void onError(int errorCode, long descriptionPointer) {
String description = GLFWErrorCallback.getDescription(descriptionPointer);
String errorCodeName;
if (ERROR_CODES.hasConstant(errorCode)) {
errorCodeName = ERROR_CODES.getName(errorCode);
} else {
errorCodeName = "<unknown " + Integer.toHexString(errorCode) + ">";
}
throw CrashReports.report(null, "GLFW error detected: " + errorCodeName + " %s", description);
}
}

View File

@ -19,7 +19,6 @@
package ru.windcorp.progressia.client.graphics.backend;
import glm.vec._2.i.Vec2i;
import org.lwjgl.glfw.GLFWVidMode;
import static org.lwjgl.glfw.GLFW.*;
@ -44,13 +43,6 @@ public class GraphicsBackend {
private static boolean isGLFWInitialized = false;
private static boolean isOpenGLInitialized = false;
private static boolean allowDisablingCursor;
static {
String key = GraphicsBackend.class.getName() + ".allowDisablingCursor";
allowDisablingCursor = Boolean.parseBoolean(System.getProperty(key, "true"));
}
private static boolean forceCursorToCenter = false;
private GraphicsBackend() {
}
@ -122,10 +114,6 @@ public class GraphicsBackend {
frameLength = now - frameStart;
frameStart = now;
}
if (forceCursorToCenter) {
glfwSetCursorPos(windowHandle, FRAME_SIZE.x / 2.0, FRAME_SIZE.y / 2.0);
}
}
static void endFrame() {
@ -171,27 +159,14 @@ public class GraphicsBackend {
public static void setFullscreen() {
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowMonitor(
getWindowHandle(),
glfwGetPrimaryMonitor(),
0,
0,
vidmode.width(),
vidmode.height(),
0);
glfwSetWindowMonitor(getWindowHandle(), glfwGetPrimaryMonitor(), 0, 0, vidmode.width(), vidmode.height(), 0);
isFullscreen = true;
}
public static void setWindowed() {
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowMonitor(
getWindowHandle(),
0,
(vidmode.width() - getFrameWidth()) / 2,
(vidmode.height() - getFrameHeight()) / 2,
getFrameWidth(),
getFrameHeight(),
0);
glfwSetWindowMonitor(getWindowHandle(), 0, (vidmode.width() - getFrameWidth()) / 2,
(vidmode.height() - getFrameHeight()) / 2, getFrameWidth(), getFrameHeight(), 0);
isFullscreen = false;
}
@ -206,18 +181,10 @@ public class GraphicsBackend {
}
public static boolean isMouseCaptured() {
if (!allowDisablingCursor) {
return forceCursorToCenter;
}
return glfwGetInputMode(windowHandle, GLFW_CURSOR) == GLFW_CURSOR_DISABLED;
}
public static void setMouseCaptured(boolean capture) {
if (!allowDisablingCursor) {
forceCursorToCenter = capture;
return;
}
int mode = capture ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL;
glfwSetInputMode(windowHandle, GLFW_CURSOR, mode);

View File

@ -69,10 +69,6 @@ public class GraphicsInterface {
InputHandler.register(listener);
}
public static void unsubscribeFromInputEvents(Object listener) {
InputHandler.unregister(listener);
}
public static void startNextLayer() {
GraphicsBackend.startNextLayer();
}

View File

@ -39,7 +39,6 @@ public class InputHandler {
public void initialize(int key, int scancode, int action, int mods) {
this.setTime(GraphicsInterface.getTime());
this.setConsumed(false);
this.key = key;
this.scancode = scancode;
this.action = action;
@ -50,17 +49,11 @@ public class InputHandler {
private static final ModifiableKeyEvent THE_KEY_EVENT = new ModifiableKeyEvent();
static void handleKeyInput(
long window,
int key,
int scancode,
int action,
int mods
) {
static void handleKeyInput(long window, int key, int scancode, int action, int mods) {
if (GraphicsBackend.getWindowHandle() != window)
return;
THE_KEY_EVENT.initialize(key, scancode, action, mods);
INPUT_EVENT_BUS.post(THE_KEY_EVENT);
dispatch(THE_KEY_EVENT);
switch (action) {
case GLFW.GLFW_PRESS:
@ -72,12 +65,7 @@ public class InputHandler {
}
}
static void handleMouseButtonInput(
long window,
int key,
int action,
int mods
) {
static void handleMouseButtonInput(long window, int key, int action, int mods) {
handleKeyInput(window, key, Integer.MAX_VALUE - key, action, mods);
}
@ -91,7 +79,6 @@ public class InputHandler {
public void initialize(double x, double y) {
this.setTime(GraphicsInterface.getTime());
this.setConsumed(false);
getNewPosition().set(x, y);
}
@ -99,11 +86,7 @@ public class InputHandler {
private static final ModifiableCursorMoveEvent THE_CURSOR_MOVE_EVENT = new ModifiableCursorMoveEvent();
static void handleMouseMoveInput(
long window,
double x,
double y
) {
static void handleMouseMoveInput(long window, double x, double y) {
if (GraphicsBackend.getWindowHandle() != window)
return;
y = GraphicsInterface.getFrameHeight() - y; // Flip y axis
@ -111,7 +94,7 @@ public class InputHandler {
InputTracker.initializeCursorPosition(x, y);
THE_CURSOR_MOVE_EVENT.initialize(x, y);
INPUT_EVENT_BUS.post(THE_CURSOR_MOVE_EVENT);
dispatch(THE_CURSOR_MOVE_EVENT);
InputTracker.getCursorPosition().set(x, y);
}
@ -126,7 +109,6 @@ public class InputHandler {
public void initialize(double xOffset, double yOffset) {
this.setTime(GraphicsInterface.getTime());
this.setConsumed(false);
this.getOffset().set(xOffset, yOffset);
}
@ -134,15 +116,11 @@ public class InputHandler {
private static final ModifiableWheelScrollEvent THE_WHEEL_SCROLL_EVENT = new ModifiableWheelScrollEvent();
static void handleWheelScroll(
long window,
double xoffset,
double yoffset
) {
static void handleWheelScroll(long window, double xoffset, double yoffset) {
if (GraphicsBackend.getWindowHandle() != window)
return;
THE_WHEEL_SCROLL_EVENT.initialize(xoffset, yoffset);
INPUT_EVENT_BUS.post(THE_WHEEL_SCROLL_EVENT);
dispatch(THE_WHEEL_SCROLL_EVENT);
}
// FrameResizeEvent
@ -155,7 +133,6 @@ public class InputHandler {
public void initialize(int width, int height) {
this.setTime(GraphicsInterface.getTime());
this.setConsumed(false);
this.getNewSize().set(width, height);
}
@ -166,22 +143,19 @@ public class InputHandler {
/*
* NB: this is NOT a GLFW callback, the raw callback is in GraphicsBackend
*/
static void handleFrameResize(
int width,
int height
) {
static void handleFrameResize(int width, int height) {
THE_FRAME_RESIZE_EVENT.initialize(width, height);
INPUT_EVENT_BUS.post(THE_FRAME_RESIZE_EVENT);
dispatch(THE_FRAME_RESIZE_EVENT);
}
// Misc
private static void dispatch(InputEvent event) {
INPUT_EVENT_BUS.post(event);
}
public static void register(Object listener) {
INPUT_EVENT_BUS.register(listener);
}
public static void unregister(Object listener) {
INPUT_EVENT_BUS.unregister(listener);
}
}

View File

@ -24,10 +24,7 @@ import gnu.trove.set.hash.TIntHashSet;
public class InputTracker {
private static final Vec2d CURSOR_POSITION = new Vec2d(
Double.NaN,
Double.NaN
);
private static final Vec2d CURSOR_POSITION = new Vec2d(Double.NaN, Double.NaN);
private static final TIntSet PRESSED_KEYS = new TIntHashSet(256);

View File

@ -22,24 +22,9 @@ import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.system.MemoryUtil.*;
import java.io.IOException;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWImage;
import org.lwjgl.opengl.GL;
import com.google.common.eventbus.Subscribe;
import ru.windcorp.progressia.Progressia;
import ru.windcorp.progressia.client.graphics.GUI;
import ru.windcorp.progressia.client.graphics.input.FrameResizeEvent;
import ru.windcorp.progressia.client.graphics.input.InputEvent;
import ru.windcorp.progressia.client.graphics.texture.TextureDataEditor;
import ru.windcorp.progressia.client.graphics.texture.TextureLoader;
import ru.windcorp.progressia.client.graphics.texture.TextureSettings;
import ru.windcorp.progressia.common.resource.Resource;
import ru.windcorp.progressia.common.resource.ResourceManager;
import ru.windcorp.progressia.common.util.crash.CrashReports;
class LWJGLInitializer {
@ -56,7 +41,6 @@ class LWJGLInitializer {
setupWindowCallbacks();
glfwShowWindow(GraphicsBackend.getWindowHandle());
GraphicsBackend.onFrameResized(GraphicsBackend.getWindowHandle(), 800, 600);
}
private static void checkEnvironment() {
@ -64,12 +48,8 @@ class LWJGLInitializer {
}
private static void initializeGLFW() {
GLFWErrorCallback.create(new GLFWErrorHandler()::onError).set();
if (!glfwInit()) {
throw CrashReports.report(null, "GLFW could not be initialized: glfwInit() has failed");
}
// TODO Do GLFW error handling: check glfwInit, setup error callback
glfwInit();
GraphicsBackend.setGLFWInitialized(true);
}
@ -77,13 +57,11 @@ class LWJGLInitializer {
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE);
glfwWindowHint(GLFW_MAXIMIZED, GLFW_TRUE);
String windowTitle = Progressia.getName() + " " + Progressia.getFullerVersion();
long handle = glfwCreateWindow(800, 600, windowTitle, NULL, NULL);
long handle = glfwCreateWindow(900, 900, "ProgressiaTest", NULL, NULL);
if (handle == 0) {
throw CrashReports.report(null, "Could not create game window");
}
// TODO Check that handle != NULL
GraphicsBackend.setWindowHandle(handle);
@ -97,30 +75,8 @@ class LWJGLInitializer {
}
private static void createWindowIcons() {
if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND) {
// Wayland does not support changing window icons
return;
}
// TODO Auto-generated method stub
final String prefix = "assets/icons/";
String[] sizes = ResourceManager.getResource(prefix + "logoSizes.txt").readAsString().split(" ");
try (GLFWImage.Buffer buffer = GLFWImage.malloc(sizes.length)) {
for (int i = 0; i < sizes.length; ++i) {
Resource resource = ResourceManager.getResource(prefix + "logo" + sizes[i].trim() + ".png");
TextureDataEditor icon = TextureLoader.loadPixels(resource, new TextureSettings(false, true));
buffer.position(i)
.width(icon.getContentWidth())
.height(icon.getContentHeight())
.pixels(icon.getData().getData());
}
glfwSetWindowIcon(GraphicsBackend.getWindowHandle(), buffer);
} catch (IOException e) {
throw CrashReports.report(e, "Could not load window icons");
}
}
private static void initializeOpenGL() {
@ -136,35 +92,16 @@ class LWJGLInitializer {
private static void setupWindowCallbacks() {
long handle = GraphicsBackend.getWindowHandle();
glfwSetFramebufferSizeCallback(
handle,
GraphicsBackend::onFrameResized
);
glfwSetFramebufferSizeCallback(handle, GraphicsBackend::onFrameResized);
glfwSetKeyCallback(handle, InputHandler::handleKeyInput);
glfwSetMouseButtonCallback(
handle,
InputHandler::handleMouseButtonInput
);
glfwSetMouseButtonCallback(handle, InputHandler::handleMouseButtonInput);
glfwSetCursorPosCallback(handle, InputHandler::handleMouseMoveInput);
glfwSetScrollCallback(handle, InputHandler::handleWheelScroll);
GraphicsInterface.subscribeToInputEvents(new Object() {
@Subscribe
public void onFrameResized(FrameResizeEvent event) {
GUI.invalidateEverything();
}
@Subscribe
public void onInputEvent(InputEvent event) {
GUI.dispatchInput(event);
}
});
GraphicsInterface.subscribeToInputEvents(GUI.getEventSubscriber());
}
}

View File

@ -34,19 +34,13 @@ public class OpenGLObjectTracker {
private static final ReferenceQueue<OpenGLDeletable> DELETE_QUEUE = new ReferenceQueue<>();
public synchronized static void register(OpenGLDeletable object, IntConsumer glDeleter) {
GLPhantomReference<OpenGLDeletable> glRef = new GLPhantomReference<>(
object,
DELETE_QUEUE,
object.getHandle(),
glDeleter
);
GLPhantomReference<OpenGLDeletable> glRef = new GLPhantomReference<>(object, DELETE_QUEUE, object.getHandle(),
glDeleter);
TO_DELETE.add(glRef);
}
public static void deleteAllObjects() {
for (
GLPhantomReference<OpenGLDeletable> glRef : TO_DELETE
) {
for (GLPhantomReference<OpenGLDeletable> glRef : TO_DELETE) {
glRef.clear();
}
}
@ -75,20 +69,16 @@ public class OpenGLObjectTracker {
* It is possible to create a phantom reference with a {@code null}
* queue, but such a reference is completely useless: Its {@code get}
* method will always return {@code null} and, since it does not have a
* queue,
* it will never be enqueued.
* queue, it will never be enqueued.
*
* @param referent the object the new phantom reference will refer to
* @param q the queue with which the reference is to be
* registered,
* or {@code null} if registration is not required
* @param referent
* the object the new phantom reference will refer to
* @param q
* the queue with which the reference is to be registered, or
* {@code null} if registration is not required
*/
public GLPhantomReference(
T referent,
ReferenceQueue<? super T> q,
int referentGLhandle,
IntConsumer GLDeleter
) {
public GLPhantomReference(T referent, ReferenceQueue<? super T> q, int referentGLhandle,
IntConsumer GLDeleter) {
super(referent, q);
this.referentGLhandle = referentGLhandle;
this.GLDeleter = GLDeleter;

View File

@ -41,11 +41,7 @@ public class RenderTaskQueue {
HANDLER.invokeNow(task);
}
public static <E extends Exception> void waitAndInvoke(
ThrowingRunnable<E> task
)
throws InterruptedException,
E {
public static <E extends Exception> void waitAndInvoke(ThrowingRunnable<E> task) throws InterruptedException, E {
HANDLER.waitAndInvoke(task);
}

View File

@ -23,9 +23,7 @@ import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW;
import static org.lwjgl.opengl.GL15.GL_STREAM_DRAW;
public enum Usage { // TODO add _COPY and _READ, pref. as another enum
STATIC(GL_STATIC_DRAW),
DYNAMIC(GL_DYNAMIC_DRAW),
STREAM(GL_STREAM_DRAW);
STATIC(GL_STATIC_DRAW), DYNAMIC(GL_DYNAMIC_DRAW), STREAM(GL_STREAM_DRAW);
private final int glCode;

View File

@ -28,8 +28,7 @@ import ru.windcorp.progressia.client.graphics.backend.OpenGLObjectTracker.OpenGL
public class VertexBufferObject implements OpenGLDeletable {
public static enum BindTarget {
ARRAY(GL_ARRAY_BUFFER),
ELEMENT_ARRAY(GL_ELEMENT_ARRAY_BUFFER);
ARRAY(GL_ARRAY_BUFFER), ELEMENT_ARRAY(GL_ELEMENT_ARRAY_BUFFER);
private final int glCode;

View File

@ -32,12 +32,7 @@ public class CombinedShader extends Shader {
for (int i = 1; i < resources.length; ++i) {
if (ShaderType.guessByResourceName(resources[i]) != first) {
throw new IllegalArgumentException(
"Deduced shader types of "
+ resources[0]
+ " and "
+ resources[i]
+ " differ"
);
"Deduced shader types of " + resources[0] + " and " + resources[i] + " differ");
}
}
@ -71,19 +66,8 @@ public class CombinedShader extends Shader {
if (contents.codePointAt(versionIndex) == '#') {
final String versionAnnotation = "#version ";
if (
contents.regionMatches(
versionIndex,
versionAnnotation,
0,
versionAnnotation.length()
)
) {
contents = contents.substring(
versionIndex
+ versionAnnotation.length()
+ "120".length()
);
if (contents.regionMatches(versionIndex, versionAnnotation, 0, versionAnnotation.length())) {
contents = contents.substring(versionIndex + versionAnnotation.length() + "120".length());
}
}

View File

@ -57,10 +57,7 @@ public class Shader implements OpenGLDeletable {
if (resource.contains("fsh"))
return FRAGMENT;
throw new IllegalArgumentException(
"Cannot deduce shader type from resource name \"" +
resource + "\""
);
throw new IllegalArgumentException("Cannot deduce shader type from resource name \"" + resource + "\"");
}
}
@ -90,10 +87,7 @@ public class Shader implements OpenGLDeletable {
}
public Shader(String resource) {
this(
ShaderType.guessByResourceName(resource),
getShaderResource(resource).readAsString()
);
this(ShaderType.guessByResourceName(resource), getShaderResource(resource).readAsString());
}
@Override

View File

@ -51,104 +51,29 @@ public class AttributeVertexArray extends Attribute {
}
}
public void set(
int size,
boolean normalized,
int stride,
ByteBuffer pointer
) {
glVertexAttribPointer(
handle,
size,
GL_BYTE,
normalized,
stride,
pointer
);
public void set(int size, boolean normalized, int stride, ByteBuffer pointer) {
glVertexAttribPointer(handle, size, GL_BYTE, normalized, stride, pointer);
}
public void set(
int size,
boolean normalized,
int stride,
FloatBuffer pointer
) {
glVertexAttribPointer(
handle,
size,
GL_FLOAT,
normalized,
stride,
pointer
);
public void set(int size, boolean normalized, int stride, FloatBuffer pointer) {
glVertexAttribPointer(handle, size, GL_FLOAT, normalized, stride, pointer);
}
public void set(
int size,
boolean normalized,
int stride,
IntBuffer pointer
) {
glVertexAttribPointer(
handle,
size,
GL_INT,
normalized,
stride,
pointer
);
public void set(int size, boolean normalized, int stride, IntBuffer pointer) {
glVertexAttribPointer(handle, size, GL_INT, normalized, stride, pointer);
}
public void set(
int size,
boolean normalized,
int stride,
ShortBuffer pointer
) {
glVertexAttribPointer(
handle,
size,
GL_SHORT,
normalized,
stride,
pointer
);
public void set(int size, boolean normalized, int stride, ShortBuffer pointer) {
glVertexAttribPointer(handle, size, GL_SHORT, normalized, stride, pointer);
}
public void set(
int size,
int type,
boolean normalized,
int stride,
long pointer
) {
glVertexAttribPointer(
handle,
size,
type,
normalized,
stride,
pointer
);
public void set(int size, int type, boolean normalized, int stride, long pointer) {
glVertexAttribPointer(handle, size, type, normalized, stride, pointer);
}
public void set(
int size,
int type,
boolean normalized,
int stride,
VertexBufferObject vbo,
long offset
) {
public void set(int size, int type, boolean normalized, int stride, VertexBufferObject vbo, long offset) {
glBindBuffer(GL_ARRAY_BUFFER, vbo.getHandle());
glVertexAttribPointer(
handle,
size,
type,
normalized,
stride,
offset
);
glVertexAttribPointer(handle, size, type, normalized, stride, offset);
}
}

View File

@ -37,8 +37,7 @@ public abstract class FlatRenderHelper extends ShapeRenderHelper {
float width = GraphicsInterface.getFrameWidth();
float height = GraphicsInterface.getFrameHeight();
return finalTransform.identity().translate(-1, -1, 0)
.scale(2 / width, 2 / height, 1 / MAX_DEPTH)
return finalTransform.identity().translate(-1, -1, 0).scale(2 / width, 2 / height, 1 / MAX_DEPTH)
.mul(getTransform());
}

View File

@ -33,10 +33,8 @@ public class FlatRenderProgram extends ShapeRenderProgram {
private static FlatRenderProgram def = null;
public static void init() {
def = new FlatRenderProgram(
new String[] { "FlatDefault.vertex.glsl" },
new String[] { "FlatDefault.fragment.glsl" }
);
def = new FlatRenderProgram(new String[] { "FlatDefault.vertex.glsl" },
new String[] { "FlatDefault.fragment.glsl" });
}
public static FlatRenderProgram getDefault() {
@ -48,20 +46,13 @@ public class FlatRenderProgram extends ShapeRenderProgram {
private static final String FLAT_VERTEX_SHADER_RESOURCE = "Flat.vertex.glsl";
private static final String FLAT_FRAGMENT_SHADER_RESOURCE = "Flat.fragment.glsl";
private static final String MASK_COUNT_UNIFORM_NAME = "maskCount",
MASKS_UNIFORM_NAME = "masks";
private static final String MASK_COUNT_UNIFORM_NAME = "maskCount", MASKS_UNIFORM_NAME = "masks";
private final Uniform1Int maskCountUniform;
private final Uniform2Float masksUniform;
public FlatRenderProgram(
String[] vertexShaderResources,
String[] fragmentShaderResources
) {
super(
attachVertexShader(vertexShaderResources),
attachFragmentShader(fragmentShaderResources)
);
public FlatRenderProgram(String[] vertexShaderResources, String[] fragmentShaderResources) {
super(attachVertexShader(vertexShaderResources), attachFragmentShader(fragmentShaderResources));
this.maskCountUniform = getUniform(MASK_COUNT_UNIFORM_NAME).as1Int();
this.masksUniform = getUniform(MASKS_UNIFORM_NAME).as2Float();

View File

@ -88,8 +88,7 @@ public class Mask {
@Override
public String toString() {
return "(" + getStartX() + "; " + getStartY() +
") -> (" + getEndX() + "; " + getEndY() + ")";
return "(" + getStartX() + "; " + getStartY() + ") -> (" + getEndX() + "; " + getEndY() + ")";
}
}

View File

@ -24,9 +24,8 @@ import org.lwjgl.BufferUtils;
public class MaskStack {
private final FloatBuffer buffer = BufferUtils.createFloatBuffer(
FlatRenderProgram.MASK_STACK_SIZE * TransformedMask.SIZE_IN_FLOATS
);
private final FloatBuffer buffer = BufferUtils
.createFloatBuffer(FlatRenderProgram.MASK_STACK_SIZE * TransformedMask.SIZE_IN_FLOATS);
public void pushMask(TransformedMask mask) {
mask.writeToBuffer(buffer);

View File

@ -42,14 +42,8 @@ public class TransformedMask {
private Vec4 endXstartY = null;
private Vec4 endXendY = null;
public TransformedMask(
Vec2 origin,
Vec2 width,
Vec2 height,
Vec2 counterOrigin,
Vec2 counterWidth,
Vec2 counterHeight
) {
public TransformedMask(Vec2 origin, Vec2 width, Vec2 height, Vec2 counterOrigin, Vec2 counterWidth,
Vec2 counterHeight) {
set(origin, width, height, counterOrigin, counterWidth, counterHeight);
}
@ -61,14 +55,8 @@ public class TransformedMask {
// Do nothing
}
public TransformedMask set(
Vec2 origin,
Vec2 width,
Vec2 height,
Vec2 counterOrigin,
Vec2 counterWidth,
Vec2 counterHeight
) {
public TransformedMask set(Vec2 origin, Vec2 width, Vec2 height, Vec2 counterOrigin, Vec2 counterWidth,
Vec2 counterHeight) {
this.origin.set(origin.x, origin.y);
this.width.set(width.x, width.y);
this.height.set(height.x, height.y);
@ -112,35 +100,17 @@ public class TransformedMask {
}
private void setFields() {
origin.set(
startXstartY.x,
startXstartY.y
);
origin.set(startXstartY.x, startXstartY.y);
width.set(
endXstartY.x - startXstartY.x,
endXstartY.y - startXstartY.y
);
width.set(endXstartY.x - startXstartY.x, endXstartY.y - startXstartY.y);
height.set(
startXendY.x - startXstartY.x,
startXendY.y - startXstartY.y
);
height.set(startXendY.x - startXstartY.x, startXendY.y - startXstartY.y);
counterOrigin.set(
endXendY.x,
endXendY.y
);
counterOrigin.set(endXendY.x, endXendY.y);
counterWidth.set(
startXendY.x - endXendY.x,
startXendY.y - endXendY.y
);
counterWidth.set(startXendY.x - endXendY.x, startXendY.y - endXendY.y);
counterHeight.set(
endXstartY.x - endXendY.x,
endXstartY.y - endXendY.y
);
counterHeight.set(endXstartY.x - endXendY.x, endXstartY.y - endXendY.y);
}
public void writeToBuffer(FloatBuffer output) {

View File

@ -68,17 +68,11 @@ public class Font {
return color;
}
public Renderable assemble(
CharSequence chars,
float maxWidth
) {
public Renderable assemble(CharSequence chars, float maxWidth) {
return typeface.assembleStatic(chars, style, align, maxWidth, color);
}
public Renderable assembleDynamic(
Supplier<CharSequence> supplier,
float maxWidth
) {
public Renderable assembleDynamic(Supplier<CharSequence> supplier, float maxWidth) {
return typeface.assembleDynamic(supplier, style, align, maxWidth, color);
}
@ -102,7 +96,8 @@ public class Font {
* Creates a new {@link Font} with the specified {@code style} exactly. This
* object's style is ignored.
*
* @param style the new style
* @param style
* the new style
* @return the new font
*/
public Font withStyle(int style) {

View File

@ -45,7 +45,7 @@ public class GNUUnifontLoader {
private static final AtlasGroup ATLAS_GROUP_GNU_UNIFONT = new AtlasGroup("GNUUnifont", 1 << 12);
private static final TextureSettings TEXTURE_SETTINGS = new TextureSettings(false, false);
private static final TextureSettings TEXTURE_SETTINGS = new TextureSettings(false);
private static final int BITS_PER_HEX_DIGIT = 4;
private static final int PREFIX_LENGTH = "0000:".length();
@ -81,8 +81,7 @@ public class GNUUnifontLoader {
private static BufferedReader createReader(Resource resource) throws IOException {
return new BufferedReader(
new InputStreamReader(new GZIPInputStream(resource.getInputStream()), StandardCharsets.UTF_8)
);
new InputStreamReader(new GZIPInputStream(resource.getInputStream()), StandardCharsets.UTF_8));
}
private static Stream<String> createStream(BufferedReader reader) {
@ -97,13 +96,8 @@ public class GNUUnifontLoader {
char c = getChar(declar);
TextureDataEditor editor = new TextureDataEditor(
width,
GNUUnifont.HEIGHT,
width,
GNUUnifont.HEIGHT,
TEXTURE_SETTINGS
);
TextureDataEditor editor = new TextureDataEditor(width, GNUUnifont.HEIGHT, width, GNUUnifont.HEIGHT,
TEXTURE_SETTINGS);
for (int y = 0; y < GNUUnifont.HEIGHT; ++y) {
for (int x = 0; x < width; ++x) {
@ -165,8 +159,7 @@ public class GNUUnifontLoader {
if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'))) {
throw new IOException(
"Illegal char in declar \"" + declar + "\" at index " + i + "; expected 0-9A-F"
);
"Illegal char in declar \"" + declar + "\" at index " + i + "; expected 0-9A-F");
}
}
}
@ -190,8 +183,7 @@ public class GNUUnifontLoader {
}
private static Collector<AtlasGlyph, ?, TCharObjectMap<Texture>> createMapper() {
return Collector.of(
TCharObjectHashMap<Texture>::new,
return Collector.of(TCharObjectHashMap<Texture>::new,
(map, glyph) -> map.put(glyph.c, glyph.texture),
@ -200,8 +192,7 @@ public class GNUUnifontLoader {
return a;
},
Characteristics.UNORDERED
);
Characteristics.UNORDERED);
}
private GNUUnifontLoader() {

View File

@ -29,12 +29,8 @@ import ru.windcorp.progressia.common.util.Vectors;
public abstract class Typeface extends Named {
public static class Style {
public static final int BOLD = 1 << 0,
ITALIC = 1 << 1,
UNDERLINED = 1 << 2,
STRIKETHRU = 1 << 3,
SHADOW = 1 << 4,
OUTLINED = 1 << 5;
public static final int BOLD = 1 << 0, ITALIC = 1 << 1, UNDERLINED = 1 << 2, STRIKETHRU = 1 << 3,
SHADOW = 1 << 4, OUTLINED = 1 << 5;
public static final int PLAIN = 0;
@ -71,40 +67,19 @@ public abstract class Typeface extends Named {
super(name);
}
public abstract Renderable assembleStatic(
CharSequence chars,
int style,
float align,
float maxWidth,
Vec4 color
);
public abstract Renderable assembleStatic(CharSequence chars, int style, float align, float maxWidth, Vec4 color);
public abstract Renderable assembleDynamic(
Supplier<CharSequence> supplier,
int style,
float align,
float maxWidth,
Vec4 color
);
public abstract Renderable assembleDynamic(Supplier<CharSequence> supplier, int style, float align, float maxWidth,
Vec4 color);
public int getWidth(
CharSequence chars,
int style,
float align,
float maxWidth
) {
public int getWidth(CharSequence chars, int style, float align, float maxWidth) {
Vec2i v = Vectors.grab2i();
v = getSize(chars, style, align, maxWidth, v);
Vectors.release(v);
return v.x;
}
public int getHeight(
CharSequence chars,
int style,
float align,
float maxWidth
) {
public int getHeight(CharSequence chars, int style, float align, float maxWidth) {
Vec2i v = Vectors.grab2i();
v = getSize(chars, style, align, maxWidth, v);
Vectors.release(v);
@ -113,13 +88,7 @@ public abstract class Typeface extends Named {
public abstract int getLineHeight();
public abstract Vec2i getSize(
CharSequence chars,
int style,
float align,
float maxWidth,
Vec2i result
);
public abstract Vec2i getSize(CharSequence chars, int style, float align, float maxWidth, Vec2i result);
public abstract boolean supports(char c);

View File

@ -43,9 +43,9 @@ public abstract class BasicButton extends Component {
private boolean isPressed = false;
private final Collection<Consumer<BasicButton>> actions = Collections.synchronizedCollection(new ArrayList<>());
public BasicButton(String name, Label label) {
public BasicButton(String name, String label, Font labelFont) {
super(name);
this.label = label;
this.label = new Label(name + ".Label", labelFont, label);
setLayout(new LayoutAlign(10));
addChild(this.label);
@ -54,17 +54,18 @@ public abstract class BasicButton extends Component {
reassembleAt(ARTrigger.HOVER, ARTrigger.FOCUS, ARTrigger.ENABLE);
// Click triggers
addInputListener(KeyEvent.class, e -> {
if (e.isRepeat())
return;
if (
addListener(KeyEvent.class, e -> {
if (e.isRepeat()) {
return false;
} else if (
e.isLeftMouseButton() ||
e.getKey() == GLFW.GLFW_KEY_SPACE ||
e.getKey() == GLFW.GLFW_KEY_ENTER
) {
setPressed(e.isPress());
e.consume();
return true;
} else {
return false;
}
});
@ -103,10 +104,6 @@ public abstract class BasicButton extends Component {
});
}
public BasicButton(String name, String label, Font labelFont) {
this(name, new Label(name + ".Label", labelFont, label));
}
public BasicButton(String name, String label) {
this(name, label, new Font());
}
@ -123,7 +120,6 @@ public abstract class BasicButton extends Component {
public void setPressed(boolean isPressed) {
if (this.isPressed != isPressed) {
this.isPressed = isPressed;
requestReassembly();
if (isPressed) {
takeFocus();

View File

@ -18,8 +18,10 @@
package ru.windcorp.progressia.client.graphics.gui;
import glm.vec._4.Vec4;
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
import ru.windcorp.progressia.client.graphics.font.Font;
import ru.windcorp.progressia.client.graphics.Colors;
public class Button extends BasicButton {
@ -27,36 +29,51 @@ public class Button extends BasicButton {
super(name, label, labelFont);
}
public Button(String name, Label label) {
super(name, label);
}
public Button(String name, String label) {
this(name, label, new Font());
}
@Override
protected void assembleSelf(RenderTarget target) {
String state;
if (!isEnabled()) {
state = "Disabled";
} else if (isPressed()) {
state = "Pressed";
} else if (isHovered()) {
state = "Hovered";
} else if (isFocused()) {
state = "Focused";
} else {
state = "Inactive";
}
// Border
target.fill(getX(), getY(), getWidth(), getHeight(), ColorScheme.get("Core:ButtonBorder" + state));
Vec4 borderColor;
if (isPressed() || isHovered() || isFocused()) {
borderColor = Colors.BLUE;
} else {
borderColor = Colors.LIGHT_GRAY;
}
target.fill(getX(), getY(), getWidth(), getHeight(), borderColor);
// Inside area
target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, ColorScheme.get("Core:ButtonFill" + state));
if (isPressed()) {
// Do nothing
} else {
Vec4 backgroundColor;
if (isHovered() && isEnabled()) {
backgroundColor = Colors.HOVER_BLUE;
} else {
backgroundColor = Colors.WHITE;
}
target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, backgroundColor);
}
// Change label font color
getLabel().setFont(getLabel().getFont().withColor(ColorScheme.get("Core:ButtonText" + state)));
if (isPressed()) {
getLabel().setFont(getLabel().getFont().withColor(Colors.WHITE));
} else {
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
}
}
@Override
protected void postAssembleSelf(RenderTarget target) {
// Apply disable tint
if (!isEnabled()) {
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF));
}
}
}

View File

@ -18,6 +18,8 @@
package ru.windcorp.progressia.client.graphics.gui;
import glm.vec._2.i.Vec2i;
import glm.vec._4.Vec4;
import ru.windcorp.progressia.client.graphics.Colors;
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
import ru.windcorp.progressia.client.graphics.font.Font;
import ru.windcorp.progressia.client.graphics.font.Typefaces;
@ -41,28 +43,34 @@ public class Checkbox extends BasicButton {
int x = getX();
int y = getY() + (getHeight() - size) / 2;
String state;
if (!Checkbox.this.isEnabled()) {
state = "Disabled";
} else if (Checkbox.this.isPressed()) {
state = "Pressed";
} else if (Checkbox.this.isHovered()) {
state = "Hovered";
} else if (Checkbox.this.isFocused()) {
state = "Focused";
} else {
state = "Inactive";
}
// Border
target.fill(x, y, size, size, ColorScheme.get("Core:CheckboxBorder" + state));
Vec4 borderColor;
if (Checkbox.this.isPressed() || Checkbox.this.isHovered() || Checkbox.this.isFocused()) {
borderColor = Colors.BLUE;
} else {
borderColor = Colors.LIGHT_GRAY;
}
target.fill(x, y, size, size, borderColor);
// Inside area
target.fill(x + 2, y + 2, size - 4, size - 4, ColorScheme.get("Core:CheckboxFill" + state));
if (Checkbox.this.isPressed()) {
// Do nothing
} else {
Vec4 backgroundColor;
if (Checkbox.this.isHovered() && Checkbox.this.isEnabled()) {
backgroundColor = Colors.HOVER_BLUE;
} else {
backgroundColor = Colors.WHITE;
}
target.fill(x + 2, y + 2, size - 4, size - 4, backgroundColor);
}
// "Tick"
if (Checkbox.this.isChecked()) {
target.fill(x + 4, y + 4, size - 8, size - 8, ColorScheme.get("Core:CheckboxCheck" + state));
target.fill(x + 4, y + 4, size - 8, size - 8, Colors.BLUE);
}
}
@ -120,21 +128,22 @@ public class Checkbox extends BasicButton {
@Override
protected void assembleSelf(RenderTarget target) {
String state;
if (!Checkbox.this.isEnabled()) {
state = "Disabled";
} else if (Checkbox.this.isPressed()) {
state = "Pressed";
} else if (Checkbox.this.isHovered()) {
state = "Hovered";
} else if (Checkbox.this.isFocused()) {
state = "Focused";
// Change label font color
if (isPressed()) {
getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE));
} else {
state = "Inactive";
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
}
}
// Change label font color
getLabel().setFont(getLabel().getFont().withColor(ColorScheme.get("Core:CheckboxText" + state)));
@Override
protected void postAssembleSelf(RenderTarget target) {
// Apply disable tint
if (!isEnabled()) {
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF));
}
}
}

View File

@ -1,145 +0,0 @@
/*
* Progressia
* Copyright (C) 2020-2022 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.graphics.gui;
import java.util.HashMap;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
import glm.vec._4.Vec4;
import ru.windcorp.jputil.SyntaxException;
import ru.windcorp.jputil.chars.StringUtil;
import ru.windcorp.progressia.common.resource.Resource;
import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.common.util.namespaces.IllegalIdException;
import ru.windcorp.progressia.common.util.namespaces.NamespacedUtil;
public class ColorScheme {
private static Map<String, Vec4> defaultScheme;
public static Vec4 get(String key) {
Vec4 color = defaultScheme.get(key);
if (color == null) {
throw CrashReports.report(null, "ColorScheme does not contain color %s", key);
}
return color;
}
public static void load(Resource resource) {
Map<String, Vec4> tmpMap = new HashMap<>();
try {
for (String fullLine : StringUtil.split(resource.readAsString(), '\n')) {
String line = fullLine.trim();
if (line.isEmpty() || line.startsWith("#")) {
continue;
}
String[] parts = StringUtil.split(line, '=', 2);
if (parts[1] == null) {
throw new SyntaxException("Could not parse \"" + line + "\": '=' not found");
}
String key = parts[0].trim();
checkKeyName(key);
if (tmpMap.containsKey(key)) {
throw new SyntaxException("Duplicate key " + key);
}
String value = parts[1].trim();
Vec4 color;
if (value.startsWith("#")) {
color = parseValueAsHex(value);
} else if (value.startsWith("$")) {
color = parseValueAsReference(value, tmpMap);
} else {
throw new SyntaxException("Unknown value format \"" + value + "\"");
}
tmpMap.put(key, color);
}
} catch (SyntaxException e) {
throw CrashReports.report(e, "Could not load ColorScheme from %s", resource);
}
defaultScheme = ImmutableMap.copyOf(tmpMap);
}
private static void checkKeyName(String key) throws SyntaxException {
try {
NamespacedUtil.checkId(key);
} catch (IllegalIdException e) {
throw new SyntaxException("Illegal key name \"" + key + "\"", e);
}
}
private static int parseHex(String from, int start, int length) {
return Integer.parseInt(from.substring(start, start + length), 0x10);
}
private static Vec4 parseValueAsHex(String value) throws SyntaxException {
int a = 0xFF;
int r, g, b;
switch (value.length() - 1) {
case 3:
// #RGB
r = parseHex(value, 1, 1) * 0x11;
g = parseHex(value, 2, 1) * 0x11;
b = parseHex(value, 3, 1) * 0x11;
break;
case 4:
// #ARGB
a = parseHex(value, 1, 1) * 0x11;
r = parseHex(value, 2, 1) * 0x11;
g = parseHex(value, 3, 1) * 0x11;
b = parseHex(value, 4, 1) * 0x11;
break;
case 6:
// #RRGGBB
r = parseHex(value, 1, 2);
g = parseHex(value, 3, 2);
b = parseHex(value, 5, 2);
break;
case 8:
// #AARRGGBB
a = parseHex(value, 1, 2);
r = parseHex(value, 3, 2);
g = parseHex(value, 5, 2);
b = parseHex(value, 7, 2);
break;
default:
throw new SyntaxException("Could not parse hex color \"" + value + "\": expecting #RGB, #ARGB, #RRGGBB or #AARRGGBB");
}
return new Vec4(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
}
private static Vec4 parseValueAsReference(String value, Map<String, Vec4> map) throws SyntaxException {
String otherKey = value.substring(1);
checkKeyName(otherKey);
if (!map.containsKey(otherKey)) {
throw new SyntaxException("Key $" + otherKey + " not found");
}
return map.get(otherKey);
}
}

View File

@ -25,6 +25,8 @@ import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import org.lwjgl.glfw.GLFW;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
@ -37,10 +39,9 @@ import ru.windcorp.progressia.client.graphics.gui.event.EnableEvent;
import ru.windcorp.progressia.client.graphics.gui.event.FocusEvent;
import ru.windcorp.progressia.client.graphics.gui.event.HoverEvent;
import ru.windcorp.progressia.client.graphics.gui.event.ParentChangedEvent;
import ru.windcorp.progressia.client.graphics.input.CursorMoveEvent;
import ru.windcorp.progressia.client.graphics.input.InputEvent;
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
import ru.windcorp.progressia.client.graphics.input.bus.Input;
import ru.windcorp.progressia.client.graphics.input.bus.InputBus;
import ru.windcorp.progressia.client.graphics.input.bus.InputListener;
import ru.windcorp.progressia.common.util.Named;
@ -54,7 +55,7 @@ public class Component extends Named {
private Component parent = null;
private EventBus eventBus = null;
private final InputBus inputBus = new InputBus(this);
private InputBus inputBus = null;
private int x, y;
private int width, height;
@ -75,9 +76,6 @@ public class Component extends Named {
public Component(String name) {
super(name);
// Update hover flag when cursor moves
addInputListener(CursorMoveEvent.class, this::updateHoverFlag, InputBus.Option.ALWAYS);
}
public Component getParent() {
@ -524,10 +522,6 @@ public class Component extends Named {
}
}
private void updateHoverFlag(CursorMoveEvent e) {
setHovered(contains((int) InputTracker.getCursorX(), (int) InputTracker.getCursorY()));
}
public void addListener(Object listener) {
if (eventBus == null) {
eventBus = ReportingEventBus.create(getName());
@ -548,32 +542,118 @@ public class Component extends Named {
eventBus.post(event);
}
public <T extends InputEvent> void addInputListener(Class<? extends T> type, InputListener<T> listener, InputBus.Option... options) {
inputBus.register(type, listener, options);
public <T extends InputEvent> void addListener(Class<? extends T> type, boolean handlesConsumed,
InputListener<T> listener) {
if (inputBus == null) {
inputBus = new InputBus();
}
public void addKeyListener(KeyMatcher matcher, InputListener<? super KeyEvent> listener, InputBus.Option... options) {
inputBus.register(matcher, listener, options);
inputBus.register(type, handlesConsumed, listener);
}
public void removeInputListener(InputListener<?> listener) {
public <T extends InputEvent> void addListener(Class<? extends T> type, InputListener<T> listener) {
if (inputBus == null) {
inputBus = new InputBus();
}
inputBus.register(type, listener);
}
public void removeListener(InputListener<?> listener) {
if (inputBus != null) {
inputBus.unregister(listener);
}
}
protected boolean passInputToChildren(InputEvent e) {
protected void handleInput(Input input) {
if (inputBus != null && isEnabled()) {
inputBus.dispatch(input);
}
}
public void dispatchInput(Input input) {
try {
switch (input.getTarget()) {
case FOCUSED:
dispatchInputToFocused(input);
break;
case HOVERED:
dispatchInputToHovered(input);
break;
case ALL:
default:
dispatchInputToAll(input);
break;
}
} catch (Exception e) {
throw CrashReports.report(e, "Could not dispatch input to Component %s", this);
}
}
private void dispatchInputToFocused(Input input) {
Component c = findFocused();
if (c == null)
return;
if (attemptFocusTransfer(input, c))
return;
while (c != null) {
c.handleInput(input);
c = c.getParent();
}
}
private void dispatchInputToHovered(Input input) {
getChildren().forEach(child -> {
if (child.containsCursor()) {
child.setHovered(true);
if (!input.isConsumed()) {
child.dispatchInput(input);
}
} else {
child.setHovered(false);
}
});
handleInput(input);
}
private void dispatchInputToAll(Input input) {
getChildren().forEach(c -> c.dispatchInput(input));
handleInput(input);
}
private boolean attemptFocusTransfer(Input input, Component focused) {
if (input.isConsumed())
return false;
if (!(input.getEvent() instanceof KeyEvent))
return false;
KeyEvent keyInput = (KeyEvent) input.getEvent();
if (keyInput.getKey() == GLFW.GLFW_KEY_TAB && !keyInput.isRelease()) {
input.consume();
if (keyInput.hasShift()) {
focused.focusPrevious();
} else {
focused.focusNext();
}
return true;
}
InputBus getInputBus() {
return inputBus;
return false;
}
public synchronized boolean contains(int x, int y) {
return x >= getX() && x < getX() + getWidth() && y >= getY() && y < getY() + getHeight();
}
public boolean containsCursor() {
return contains((int) InputTracker.getCursorX(), (int) InputTracker.getCursorY());
}
public void requestReassembly() {
if (parent != null) {
parent.requestReassembly();
@ -724,7 +804,7 @@ public class Component extends Named {
for (ARTrigger trigger : triggers) {
if (!autoReassemblyTriggerObjects.containsKey(trigger)) {
Object triggerObject = createTriggerObject(trigger);
addListener(triggerObject);
addListener(trigger);
autoReassemblyTriggerObjects.put(trigger, triggerObject);
}
}

View File

@ -1,77 +0,0 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.graphics.gui;
import java.util.Objects;
import glm.vec._2.d.Vec2d;
import ru.windcorp.progressia.client.graphics.gui.event.DragEvent;
import ru.windcorp.progressia.client.graphics.gui.event.DragStartEvent;
import ru.windcorp.progressia.client.graphics.gui.event.DragStopEvent;
import ru.windcorp.progressia.client.graphics.input.CursorMoveEvent;
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
import ru.windcorp.progressia.client.graphics.input.bus.InputBus;
public class DragManager {
private Component component;
private boolean isDragged = false;
private final Vec2d change = new Vec2d();
public void install(Component c) {
Objects.requireNonNull(c, "c");
if (c == component) {
return;
}
if (component != null) {
throw new IllegalStateException("Already installed on " + component + "; attempted to install on " + c);
}
component = c;
c.addInputListener(CursorMoveEvent.class, this::onCursorMove, InputBus.Option.ALWAYS);
c.addKeyListener(KeyMatcher.LMB, this::onLMB, InputBus.Option.ALWAYS, InputBus.Option.IGNORE_ACTION);
}
private void onCursorMove(CursorMoveEvent e) {
if (isDragged) {
Vec2d currentChange = e.getChange(null);
change.add(currentChange);
component.dispatchEvent(new DragEvent(component, currentChange, change));
}
}
private void onLMB(KeyEvent e) {
if (isDragged && e.isRelease()) {
isDragged = false;
component.dispatchEvent(new DragStopEvent(component, change));
} else if (!isDragged && !e.isConsumed() && e.isPress() && component.isHovered()) {
isDragged = true;
change.set(0, 0);
component.dispatchEvent(new DragStartEvent(component));
e.consume();
}
}
}

View File

@ -18,17 +18,9 @@
package ru.windcorp.progressia.client.graphics.gui;
import java.util.Iterator;
import org.lwjgl.glfw.GLFW;
import ru.windcorp.progressia.client.graphics.flat.AssembledFlatLayer;
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
import ru.windcorp.progressia.client.graphics.input.InputEvent;
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
import ru.windcorp.progressia.client.graphics.input.bus.InputBus;
import ru.windcorp.progressia.common.util.LowOverheadCache;
import ru.windcorp.progressia.common.util.StashingStack;
import ru.windcorp.progressia.client.graphics.input.bus.Input;
public abstract class GUILayer extends AssembledFlatLayer {
@ -41,9 +33,7 @@ public abstract class GUILayer extends AssembledFlatLayer {
public GUILayer(String name, Layout layout) {
super(name);
getRoot().setLayout(layout);
getRoot().addInputListener(KeyEvent.class, this::attemptFocusTransfer, InputBus.Option.IGNORE_FOCUS);
}
public Component getRoot() {
@ -57,85 +47,9 @@ public abstract class GUILayer extends AssembledFlatLayer {
getRoot().assemble(target);
}
/**
* Stack frame for {@link #handleInput(InputEvent)}.
*/
private static class EventHandlingFrame {
Component component;
Iterator<Component> children;
void init(Component c) {
component = c;
children = c.getChildren().iterator();
}
void reset() {
component = null;
children = null;
}
}
/**
* Stacks for {@link #handleInput(InputEvent)}.
*/
private final LowOverheadCache<StashingStack<EventHandlingFrame>> pathCache = new LowOverheadCache<>(
() -> new StashingStack<>(64, EventHandlingFrame::new)
);
/*
* This is essentially a depth-first iteration of the component tree. The
* recursive procedure has been unrolled to reduce call stack length.
*/
@Override
public void handleInput(InputEvent event) {
StashingStack<EventHandlingFrame> path = pathCache.grab();
if (!path.isEmpty()) {
throw new IllegalStateException("path is not empty: " + path);
}
path.push().init(root);
while (!path.isEmpty()) {
Iterator<Component> it = path.peek().children;
if (it.hasNext()) {
Component c = it.next();
if (c.isEnabled()) {
if (c.getChildren().isEmpty() || !c.passInputToChildren(event)) {
c.getInputBus().dispatch(event);
} else {
path.push().init(c);
}
}
} else {
path.peek().component.getInputBus().dispatch(event);
path.pop().reset();
}
}
pathCache.release(path);
}
private void attemptFocusTransfer(KeyEvent e) {
Component focused = getRoot().findFocused();
if (focused == null) {
return;
}
if (e.getKey() == GLFW.GLFW_KEY_TAB && !e.isRelease()) {
e.consume();
if (e.hasShift()) {
focused.focusPrevious();
} else {
focused.focusNext();
}
}
protected void handleInput(Input input) {
getRoot().dispatchInput(input);
}
@Override

View File

View File

@ -85,6 +85,7 @@ public class Label extends Component {
public void setFont(Font font) {
this.font = font;
requestReassembly();
}
public String getCurrentText() {

View File

@ -20,6 +20,7 @@ package ru.windcorp.progressia.client.graphics.gui;
import java.util.Objects;
import glm.vec._4.Vec4;
import ru.windcorp.progressia.client.graphics.Colors;
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
public class Panel extends Group {
@ -35,7 +36,7 @@ public class Panel extends Group {
}
public Panel(String name, Layout layout) {
this(name, layout, ColorScheme.get("Core:Background"), ColorScheme.get("Core:Border"));
this(name, layout, Colors.WHITE, Colors.LIGHT_GRAY);
}
/**

View File

@ -21,6 +21,7 @@ import org.lwjgl.glfw.GLFW;
import glm.vec._2.i.Vec2i;
import glm.vec._4.Vec4;
import ru.windcorp.progressia.client.graphics.Colors;
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
import ru.windcorp.progressia.client.graphics.font.Font;
import ru.windcorp.progressia.client.graphics.font.Typefaces;
@ -51,28 +52,34 @@ public class RadioButton extends BasicButton {
int x = getX();
int y = getY() + (getHeight() - size) / 2;
String state;
if (!RadioButton.this.isEnabled()) {
state = "Disabled";
} else if (RadioButton.this.isPressed()) {
state = "Pressed";
} else if (RadioButton.this.isHovered()) {
state = "Hovered";
} else if (RadioButton.this.isFocused()) {
state = "Focused";
} else {
state = "Inactive";
}
// Border
cross(target, x, y, size, ColorScheme.get("Core:RadioButtonBorder" + state));
Vec4 borderColor;
if (RadioButton.this.isPressed() || RadioButton.this.isHovered() || RadioButton.this.isFocused()) {
borderColor = Colors.BLUE;
} else {
borderColor = Colors.LIGHT_GRAY;
}
cross(target, x, y, size, borderColor);
// Inside area
cross(target, x + 2, y + 2, size - 4, ColorScheme.get("Core:RadioButtonFill" + state));
if (RadioButton.this.isPressed()) {
// Do nothing
} else {
Vec4 backgroundColor;
if (RadioButton.this.isHovered() && RadioButton.this.isEnabled()) {
backgroundColor = Colors.HOVER_BLUE;
} else {
backgroundColor = Colors.WHITE;
}
cross(target, x + 2, y + 2, size - 4, backgroundColor);
}
// "Tick"
if (RadioButton.this.isChecked()) {
cross(target, x + 4, y + 4, size - 8, ColorScheme.get("Core:RadioButtonCheck" + state));
cross(target, x + 4, y + 4, size - 8, Colors.BLUE);
}
}
@ -97,22 +104,25 @@ public class RadioButton extends BasicButton {
group.addChild(basicChild);
addChild(group);
addInputListener(KeyEvent.class, e -> {
if (e.isRelease()) return;
addListener(KeyEvent.class, e -> {
if (e.isRelease()) return false;
if (e.getKey() == GLFW.GLFW_KEY_LEFT || e.getKey() == GLFW.GLFW_KEY_UP) {
if (this.group != null) {
this.group.selectPrevious();
this.group.getSelected().takeFocus();
}
e.consume();
return true;
} else if (e.getKey() == GLFW.GLFW_KEY_RIGHT || e.getKey() == GLFW.GLFW_KEY_DOWN) {
if (this.group != null) {
this.group.selectNext();
this.group.getSelected().takeFocus();
}
e.consume();
return true;
}
return false;
});
addAction(b -> setChecked(true));
@ -139,8 +149,7 @@ public class RadioButton extends BasicButton {
group.selectNext();
removeAction(group.listener);
group.buttons.remove(this);
// Clear reference if this was the only button in the group
group.getSelected();
group.getSelected(); // Clear reference if this was the only button in the group
}
this.group = group;
@ -169,28 +178,28 @@ public class RadioButton extends BasicButton {
this.checked = checked;
if (group != null) {
group.listener.accept(this); // Failsafe for manual invocations of
// setChecked()
group.listener.accept(this); // Failsafe for manual invocations of setChecked()
}
}
@Override
protected void assembleSelf(RenderTarget target) {
String state;
if (!RadioButton.this.isEnabled()) {
state = "Disabled";
} else if (RadioButton.this.isPressed()) {
state = "Pressed";
} else if (RadioButton.this.isHovered()) {
state = "Hovered";
} else if (RadioButton.this.isFocused()) {
state = "Focused";
// Change label font color
if (isPressed()) {
getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE));
} else {
state = "Inactive";
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
}
}
// Change label font color
getLabel().setFont(getLabel().getFont().withColor(ColorScheme.get("Core:RadioButtonText" + state)));
@Override
protected void postAssembleSelf(RenderTarget target) {
// Apply disable tint
if (!isEnabled()) {
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF));
}
}
}

View File

@ -1,58 +0,0 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.graphics.gui.event;
import glm.vec._2.d.Vec2d;
import ru.windcorp.progressia.client.graphics.gui.Component;
public class DragEvent extends ComponentEvent {
private final Vec2d currentChange = new Vec2d();
private final Vec2d totalChange = new Vec2d();
public DragEvent(Component component, Vec2d currentChange, Vec2d totalChange) {
super(component);
this.currentChange.set(currentChange.x, currentChange.y);
this.totalChange.set(totalChange.x, totalChange.y);
}
public Vec2d getCurrentChange() {
return currentChange;
}
public double getCurrentChangeX() {
return currentChange.x;
}
public double getCurrentChangeY() {
return currentChange.y;
}
public Vec2d getTotalChange() {
return totalChange;
}
public double getTotalChangeX() {
return totalChange.x;
}
public double getTotalChangeY() {
return totalChange.y;
}
}

View File

@ -1,28 +0,0 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.graphics.gui.event;
import ru.windcorp.progressia.client.graphics.gui.Component;
public class DragStartEvent extends ComponentEvent {
public DragStartEvent(Component component) {
super(component);
}
}

View File

@ -56,13 +56,8 @@ public class LayoutAlign implements Layout {
size.x = min(size.x, cWidth);
size.y = min(size.y, cHeight);
child.setBounds(
c.getX() +
(int) ((cWidth - size.x) * alignX) + margin,
c.getY() +
(int) ((cHeight - size.y) * alignY) + margin,
size
);
child.setBounds(c.getX() + (int) ((cWidth - size.x) * alignX) + margin,
c.getY() + (int) ((cHeight - size.y) * alignY) + margin, size);
});
}
@ -71,9 +66,7 @@ public class LayoutAlign implements Layout {
public Vec2i calculatePreferredSize(Component c) {
Vec2i result = new Vec2i(0, 0);
c.getChildren().stream()
.map(child -> child.getPreferredSize())
.forEach(size -> {
c.getChildren().stream().map(child -> child.getPreferredSize()).forEach(size -> {
result.x = max(size.x, result.x);
result.y = max(size.y, result.y);
});

View File

@ -26,9 +26,7 @@ import ru.windcorp.progressia.client.graphics.gui.Layout;
public class LayoutBorderHorizontal implements Layout {
public static final String CENTER = "Center",
LEFT = "Left",
RIGHT = "Right";
public static final String CENTER = "Center", LEFT = "Left", RIGHT = "Right";
private final int margin;
@ -51,32 +49,17 @@ public class LayoutBorderHorizontal implements Layout {
if (child.getLayoutHint() == LEFT) {
childSize = child.getPreferredSize();
left = childSize.x + margin;
child.setBounds(
c.getX(),
c.getY(),
childSize.x,
c.getHeight()
);
child.setBounds(c.getX(), c.getY(), childSize.x, c.getHeight());
} else if (child.getLayoutHint() == RIGHT) {
childSize = child.getPreferredSize();
right = childSize.x + margin;
child.setBounds(
c.getX() + c.getWidth() - childSize.x,
c.getY(),
childSize.x,
c.getHeight()
);
child.setBounds(c.getX() + c.getWidth() - childSize.x, c.getY(), childSize.x, c.getHeight());
}
}
for (Component child : c.getChildren()) {
if (child.getLayoutHint() == CENTER) {
child.setBounds(
c.getX() + left,
c.getY(),
c.getWidth() - left - right,
c.getHeight()
);
child.setBounds(c.getX() + left, c.getY(), c.getWidth() - left - right, c.getHeight());
}
}

View File

@ -26,9 +26,7 @@ import ru.windcorp.progressia.client.graphics.gui.Layout;
public class LayoutBorderVertical implements Layout {
public static final String CENTER = "Center",
UP = "Up",
DOWN = "Down";
public static final String CENTER = "Center", UP = "Up", DOWN = "Down";
private final int margin;
@ -51,32 +49,17 @@ public class LayoutBorderVertical implements Layout {
if (child.getLayoutHint() == UP) {
childSize = child.getPreferredSize();
top = childSize.y + margin;
child.setBounds(
c.getX(),
c.getY(),
c.getWidth(),
childSize.y
);
child.setBounds(c.getX(), c.getY(), c.getWidth(), childSize.y);
} else if (child.getLayoutHint() == DOWN) {
childSize = child.getPreferredSize();
bottom = childSize.y + margin;
child.setBounds(
c.getX(),
c.getY() + c.getHeight() - childSize.y,
c.getWidth(),
childSize.y
);
child.setBounds(c.getX(), c.getY() + c.getHeight() - childSize.y, c.getWidth(), childSize.y);
}
}
for (Component child : c.getChildren()) {
if (child.getLayoutHint() == CENTER) {
child.setBounds(
c.getX(),
c.getY() + top,
c.getWidth(),
c.getHeight() - top - bottom
);
child.setBounds(c.getX(), c.getY() + top, c.getWidth(), c.getHeight() - top - bottom);
}
}

Some files were not shown because too many files have changed in this diff Show More