alistair
3 years ago
43 changed files with 5308 additions and 0 deletions
@ -0,0 +1,25 @@ |
|||||||
|
cmake_minimum_required(VERSION 3.4.1) |
||||||
|
|
||||||
|
string(TOLOWER ${CMAKE_BUILD_TYPE} ANDROID_BUILD_DIR) |
||||||
|
set(DISTRIBUTION_DIR ${CMAKE_SOURCE_DIR}/android/distribution/android/SDL2/intermediates/ndkBuild) |
||||||
|
set(SOURCE_FILES src/audio.c src/colours.c src/datatypes.c src/environment.c src/main.c src/vect.c src/basic-lib.c src/controlscheme.c src/draw.c src/game.c src/physics.c) |
||||||
|
set(SDL_LOCATION ${CMAKE_SOURCE_DIR}/external/SDL2) |
||||||
|
|
||||||
|
add_library( SDL2 SHARED IMPORTED ) |
||||||
|
add_library( SDL2_mixer SHARED IMPORTED ) |
||||||
|
add_library( SDL2_ttf SHARED IMPORTED ) |
||||||
|
set_target_properties(SDL2 PROPERTIES IMPORTED_LOCATION |
||||||
|
${DISTRIBUTION_DIR}/${ANDROID_BUILD_DIR}/obj/local/${ANDROID_ABI}/libSDL2.so) |
||||||
|
set_target_properties(SDL2_mixer PROPERTIES IMPORTED_LOCATION |
||||||
|
${DISTRIBUTION_DIR}/${ANDROID_BUILD_DIR}/obj/local/${ANDROID_ABI}/libSDL2_mixer.so) |
||||||
|
set_target_properties(SDL2_ttf PROPERTIES IMPORTED_LOCATION |
||||||
|
${DISTRIBUTION_DIR}/${ANDROID_BUILD_DIR}/obj/local/${ANDROID_ABI}/libSDL2_ttf.so) |
||||||
|
|
||||||
|
include_directories(${SDL_LOCATION}/SDL2/SDL2/incl2) |
||||||
|
include_directories(${SDL_LOCATION}/SDL2/include) |
||||||
|
include_directories(${SDL_LOCATION}/SDL2_mixer) |
||||||
|
include_directories(${SDL_LOCATION}/SDL2_ttf) |
||||||
|
|
||||||
|
add_library( main SHARED ${SDL_LOCATION}/SDL2/src/main/android/SDL_android_main.c ${SOURCE_FILES} ) |
||||||
|
|
||||||
|
target_link_libraries( main SDL2 SDL2_mixer SDL2_ttf) |
@ -0,0 +1,20 @@ |
|||||||
|
|
||||||
|
hello-sdl2-android |
||||||
|
Copyright (C) 2017 Paul Vallet <luap.vallet@gmail.com> |
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied |
||||||
|
warranty. In no event will the authors be held liable for any damages |
||||||
|
arising from the use of this software. |
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose, |
||||||
|
including commercial applications, and to alter it and redistribute it |
||||||
|
freely, subject to the following restrictions: |
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not |
||||||
|
claim that you wrote the original software. If you use this software |
||||||
|
in a product, an acknowledgment in the product documentation would be |
||||||
|
appreciated but is not required. |
||||||
|
2. Altered source versions must be plainly marked as such, and must not be |
||||||
|
misrepresented as being the original software. |
||||||
|
3. This notice may not be removed or altered from any source distribution. |
||||||
|
|
@ -0,0 +1,56 @@ |
|||||||
|
# hello-sdl2-android |
||||||
|
|
||||||
|
## Synopsis |
||||||
|
|
||||||
|
This project is an update of the hello world project here https://github.com/stephen47/android-sdl2-gradle-template, as I couldn't find a good way to integrate a CMake built C++ project to an android application. |
||||||
|
It features a sample hello world using SDL and SDL_image. |
||||||
|
|
||||||
|
## Requirements |
||||||
|
- JDK and JRE 8 |
||||||
|
- Android SDK and NDK (with Android Build-tools 28.0.3 and Android Platform API 28, though these are configurable) |
||||||
|
- ANDROID_HOME and ANDROID_NDK_HOME environment variables set (I did this in /etc/environment) |
||||||
|
|
||||||
|
## Compiling the sample program (command line) |
||||||
|
|
||||||
|
You can download the dependencies (SDL2 and SDL2_image), compile your program and then install it on a connected device with the following commands: |
||||||
|
``` |
||||||
|
./get_dependencies |
||||||
|
cd android |
||||||
|
./gradlew assembleDebug |
||||||
|
./gradlew installDebug |
||||||
|
``` |
||||||
|
|
||||||
|
## Compiling the sample program (Android Studio 3.2.1) |
||||||
|
|
||||||
|
First download the dependencies (SDL2 and SDL2_image) as above or manually like below. Then open the ./android folder as an existing project in Android Studio. |
||||||
|
|
||||||
|
## Downloading dependencies manually |
||||||
|
|
||||||
|
Download the latest source release from SDL and SDL_image websites: |
||||||
|
|
||||||
|
https://www.libsdl.org/download-2.0.php |
||||||
|
https://www.libsdl.org/projects/SDL_image/ |
||||||
|
|
||||||
|
Unzip it, put the SDL2-x.x.x and SDL2_image-x.x.x folders in `external/SDL2` and rename them to SDL2 and SDL2_image so your project folder looks like this: |
||||||
|
``` |
||||||
|
+ android |
||||||
|
+ external |
||||||
|
| + SDL2 |
||||||
|
| | + Android.mk |
||||||
|
| | | SDL2 |
||||||
|
| | | SDL2_image |
||||||
|
``` |
||||||
|
|
||||||
|
There, it's done! |
||||||
|
|
||||||
|
## Thanks |
||||||
|
|
||||||
|
Most of the code here is inspired by these repositories: |
||||||
|
|
||||||
|
https://github.com/stephen47/android-sdl2-gradle-template (Android + gradle) |
||||||
|
|
||||||
|
https://github.com/suikki/simpleSDL/ (Android + CMake) |
||||||
|
|
||||||
|
The example libSDL2 program which draws the square on screen was found at https://stackoverflow.com/questions/21890627/drawing-a-rectangle-with-sdl2/21903973#21903973. |
||||||
|
|
||||||
|
The Google NDK example projects were very helpful: https://github.com/googlesamples/android-ndk |
@ -0,0 +1,3 @@ |
|||||||
|
distribution/ |
||||||
|
.gradle/ |
||||||
|
.idea/ |
@ -0,0 +1 @@ |
|||||||
|
.externalNativeBuild/ |
@ -0,0 +1,38 @@ |
|||||||
|
apply plugin: 'com.android.library' |
||||||
|
|
||||||
|
android { |
||||||
|
compileSdkVersion 28 |
||||||
|
buildToolsVersion "28.0.3" |
||||||
|
|
||||||
|
defaultConfig { |
||||||
|
minSdkVersion 21 |
||||||
|
targetSdkVersion 28 |
||||||
|
versionCode 1 |
||||||
|
versionName "1.0" |
||||||
|
|
||||||
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" |
||||||
|
ndk { |
||||||
|
abiFilters "armeabi-v7a" |
||||||
|
} |
||||||
|
} |
||||||
|
buildTypes { |
||||||
|
release { |
||||||
|
minifyEnabled false |
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' |
||||||
|
} |
||||||
|
} |
||||||
|
externalNativeBuild { |
||||||
|
ndkBuild { |
||||||
|
path '../../external/SDL2/Android.mk' |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
dependencies { |
||||||
|
compile fileTree(dir: 'libs', include: ['*.jar']) |
||||||
|
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { |
||||||
|
exclude group: 'com.android.support', module: 'support-annotations' |
||||||
|
}) |
||||||
|
compile 'com.android.support:appcompat-v7:28.0.0' |
||||||
|
testCompile 'junit:junit:4.12' |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
# Add project specific ProGuard rules here. |
||||||
|
# By default, the flags in this file are appended to flags specified |
||||||
|
# in /home/luap/Logiciels/android-sdk/tools/proguard/proguard-android.txt |
||||||
|
# You can edit the include path and order by changing the proguardFiles |
||||||
|
# directive in build.gradle. |
||||||
|
# |
||||||
|
# For more details, see |
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html |
||||||
|
|
||||||
|
# Add any project specific keep options here: |
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following |
||||||
|
# and specify the fully qualified class name to the JavaScript interface |
||||||
|
# class: |
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { |
||||||
|
# public *; |
||||||
|
#} |
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for |
||||||
|
# debugging stack traces. |
||||||
|
#-keepattributes SourceFile,LineNumberTable |
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to |
||||||
|
# hide the original source file name. |
||||||
|
#-renamesourcefileattribute SourceFile |
@ -0,0 +1 @@ |
|||||||
|
.externalNativeBuild/ |
@ -0,0 +1,45 @@ |
|||||||
|
apply plugin: 'com.android.application' |
||||||
|
|
||||||
|
android { |
||||||
|
compileSdkVersion 28 |
||||||
|
buildToolsVersion "28.0.3" |
||||||
|
defaultConfig { |
||||||
|
applicationId "pvallet.com.github.hello_sdl2" |
||||||
|
minSdkVersion 21 |
||||||
|
targetSdkVersion 28 |
||||||
|
versionCode 1 |
||||||
|
versionName "1.0" |
||||||
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" |
||||||
|
externalNativeBuild { |
||||||
|
cmake { |
||||||
|
cppFlags "-std=c++11 -frtti -fexceptions" |
||||||
|
} |
||||||
|
} |
||||||
|
ndk { |
||||||
|
abiFilters "armeabi-v7a" |
||||||
|
} |
||||||
|
} |
||||||
|
buildTypes { |
||||||
|
release { |
||||||
|
minifyEnabled false |
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' |
||||||
|
} |
||||||
|
} |
||||||
|
externalNativeBuild { |
||||||
|
cmake { |
||||||
|
path "../../CMakeLists.txt" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
dependencies { |
||||||
|
compile fileTree(dir: 'libs', include: ['*.jar']) |
||||||
|
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { |
||||||
|
exclude group: 'com.android.support', module: 'support-annotations' |
||||||
|
}) |
||||||
|
compile 'com.android.support:appcompat-v7:28.0.0' |
||||||
|
// Uncomment this line to build SDL2 |
||||||
|
// Uncomment a line in ../gradle.settings as well |
||||||
|
compile project(':SDL2') |
||||||
|
testCompile 'junit:junit:4.12' |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
# Add project specific ProGuard rules here. |
||||||
|
# By default, the flags in this file are appended to flags specified |
||||||
|
# in /home/luap/Logiciels/android-sdk/tools/proguard/proguard-android.txt |
||||||
|
# You can edit the include path and order by changing the proguardFiles |
||||||
|
# directive in build.gradle. |
||||||
|
# |
||||||
|
# For more details, see |
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html |
||||||
|
|
||||||
|
# Add any project specific keep options here: |
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following |
||||||
|
# and specify the fully qualified class name to the JavaScript interface |
||||||
|
# class: |
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { |
||||||
|
# public *; |
||||||
|
#} |
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for |
||||||
|
# debugging stack traces. |
||||||
|
#-keepattributes SourceFile,LineNumberTable |
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to |
||||||
|
# hide the original source file name. |
||||||
|
#-renamesourcefileattribute SourceFile |
@ -0,0 +1,31 @@ |
|||||||
|
// Top-level build file where you can add configuration options common to all sub-projects/modules. |
||||||
|
|
||||||
|
buildscript { |
||||||
|
repositories { |
||||||
|
google() |
||||||
|
jcenter() |
||||||
|
} |
||||||
|
dependencies { |
||||||
|
classpath 'com.android.tools.build:gradle:3.2.1' |
||||||
|
|
||||||
|
// NOTE: Do not place your application dependencies here; they belong |
||||||
|
// in the individual module build.gradle files |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Instead of having a build dir inside android app dir use the same project top level build dir to reduce clutter |
||||||
|
buildDir = file("distribution/${rootProject.name}/${project.name}") |
||||||
|
subprojects { |
||||||
|
buildDir = file("../distribution/${rootProject.name}/${project.name}") |
||||||
|
} |
||||||
|
|
||||||
|
allprojects { |
||||||
|
repositories { |
||||||
|
google() |
||||||
|
jcenter() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
task clean(type: Delete) { |
||||||
|
delete rootProject.buildDir |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
# Project-wide Gradle settings. |
||||||
|
|
||||||
|
# IDE (e.g. Android Studio) users: |
||||||
|
# Gradle settings configured through the IDE *will override* |
||||||
|
# any settings specified in this file. |
||||||
|
|
||||||
|
# For more details on how to configure your build environment visit |
||||||
|
# http://www.gradle.org/docs/current/userguide/build_environment.html |
||||||
|
|
||||||
|
# Specifies the JVM arguments used for the daemon process. |
||||||
|
# The setting is particularly useful for tweaking memory settings. |
||||||
|
org.gradle.jvmargs=-Xmx1536m |
||||||
|
|
||||||
|
# When configured, Gradle will run in incubating parallel mode. |
||||||
|
# This option should only be used with decoupled projects. More details, visit |
||||||
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects |
||||||
|
# org.gradle.parallel=true |
Binary file not shown.
@ -0,0 +1,6 @@ |
|||||||
|
#Wed Jul 05 15:54:11 CEST 2017 |
||||||
|
distributionBase=GRADLE_USER_HOME |
||||||
|
distributionPath=wrapper/dists |
||||||
|
zipStoreBase=GRADLE_USER_HOME |
||||||
|
zipStorePath=wrapper/dists |
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip |
@ -0,0 +1,160 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
|
||||||
|
############################################################################## |
||||||
|
## |
||||||
|
## Gradle start up script for UN*X |
||||||
|
## |
||||||
|
############################################################################## |
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. |
||||||
|
DEFAULT_JVM_OPTS="" |
||||||
|
|
||||||
|
APP_NAME="Gradle" |
||||||
|
APP_BASE_NAME=`basename "$0"` |
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value. |
||||||
|
MAX_FD="maximum" |
||||||
|
|
||||||
|
warn ( ) { |
||||||
|
echo "$*" |
||||||
|
} |
||||||
|
|
||||||
|
die ( ) { |
||||||
|
echo |
||||||
|
echo "$*" |
||||||
|
echo |
||||||
|
exit 1 |
||||||
|
} |
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false'). |
||||||
|
cygwin=false |
||||||
|
msys=false |
||||||
|
darwin=false |
||||||
|
case "`uname`" in |
||||||
|
CYGWIN* ) |
||||||
|
cygwin=true |
||||||
|
;; |
||||||
|
Darwin* ) |
||||||
|
darwin=true |
||||||
|
;; |
||||||
|
MINGW* ) |
||||||
|
msys=true |
||||||
|
;; |
||||||
|
esac |
||||||
|
|
||||||
|
# Attempt to set APP_HOME |
||||||
|
# Resolve links: $0 may be a link |
||||||
|
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 |
||||||
|
SAVED="`pwd`" |
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null |
||||||
|
APP_HOME="`pwd -P`" |
||||||
|
cd "$SAVED" >/dev/null |
||||||
|
|
||||||
|
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" |
||||||
|
else |
||||||
|
JAVACMD="$JAVA_HOME/bin/java" |
||||||
|
fi |
||||||
|
if [ ! -x "$JAVACMD" ] ; then |
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME |
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the |
||||||
|
location of your Java installation." |
||||||
|
fi |
||||||
|
else |
||||||
|
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 |
||||||
|
location of your Java installation." |
||||||
|
fi |
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can. |
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "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 |
||||||
|
|
||||||
|
# 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, switch paths to Windows format before running java |
||||||
|
if $cygwin ; then |
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"` |
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` |
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"` |
||||||
|
|
||||||
|
# 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=$((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 |
||||||
|
|
||||||
|
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules |
||||||
|
function splitJvmOpts() { |
||||||
|
JVM_OPTS=("$@") |
||||||
|
} |
||||||
|
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS |
||||||
|
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" |
||||||
|
|
||||||
|
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" |
@ -0,0 +1,90 @@ |
|||||||
|
@if "%DEBUG%" == "" @echo off |
||||||
|
@rem ########################################################################## |
||||||
|
@rem |
||||||
|
@rem Gradle startup script for Windows |
||||||
|
@rem |
||||||
|
@rem ########################################################################## |
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell |
||||||
|
if "%OS%"=="Windows_NT" setlocal |
||||||
|
|
||||||
|
@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= |
||||||
|
|
||||||
|
set DIRNAME=%~dp0 |
||||||
|
if "%DIRNAME%" == "" set DIRNAME=. |
||||||
|
set APP_BASE_NAME=%~n0 |
||||||
|
set APP_HOME=%DIRNAME% |
||||||
|
|
||||||
|
@rem Find java.exe |
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome |
||||||
|
|
||||||
|
set JAVA_EXE=java.exe |
||||||
|
%JAVA_EXE% -version >NUL 2>&1 |
||||||
|
if "%ERRORLEVEL%" == "0" goto init |
||||||
|
|
||||||
|
echo. |
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |
||||||
|
echo. |
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the |
||||||
|
echo location of your Java installation. |
||||||
|
|
||||||
|
goto fail |
||||||
|
|
||||||
|
:findJavaFromJavaHome |
||||||
|
set JAVA_HOME=%JAVA_HOME:"=% |
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe |
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto init |
||||||
|
|
||||||
|
echo. |
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% |
||||||
|
echo. |
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the |
||||||
|
echo location of your Java installation. |
||||||
|
|
||||||
|
goto fail |
||||||
|
|
||||||
|
:init |
||||||
|
@rem Get command-line arguments, handling Windowz variants |
||||||
|
|
||||||
|
if not "%OS%" == "Windows_NT" goto win9xME_args |
||||||
|
if "%@eval[2+2]" == "4" goto 4NT_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=%* |
||||||
|
goto execute |
||||||
|
|
||||||
|
:4NT_args |
||||||
|
@rem Get arguments from the 4NT Shell from JP Software |
||||||
|
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 %CMD_LINE_ARGS% |
||||||
|
|
||||||
|
:end |
||||||
|
@rem End local scope for the variables with windows NT shell |
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd |
||||||
|
|
||||||
|
:fail |
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of |
||||||
|
rem the _cmd.exe /c_ return code! |
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 |
||||||
|
exit /b 1 |
||||||
|
|
||||||
|
:mainEnd |
||||||
|
if "%OS%"=="Windows_NT" endlocal |
||||||
|
|
||||||
|
:omega |
@ -0,0 +1,4 @@ |
|||||||
|
include ':app' |
||||||
|
// Uncomment this line to build SDL2 |
||||||
|
// Uncomment the dependency line in app/build.gradle as well |
||||||
|
include ':SDL2' |
@ -0,0 +1,17 @@ |
|||||||
|
#!/bin/bash -x |
||||||
|
|
||||||
|
pushd external/SDL2 |
||||||
|
|
||||||
|
wget https://www.libsdl.org/release/SDL2-2.0.8.zip |
||||||
|
unzip -q SDL2-2.0.8.zip |
||||||
|
mv SDL2-2.0.8 SDL2 |
||||||
|
rm SDL2-2.0.8.zip |
||||||
|
|
||||||
|
wget https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.3.zip |
||||||
|
unzip -q SDL2_image-2.0.3.zip |
||||||
|
mv SDL2_image-2.0.3 SDL2_image |
||||||
|
rm SDL2_image-2.0.3.zip |
||||||
|
|
||||||
|
popd |
||||||
|
# No need to copy SDLActivity.java et al, repo contains those from 2.0.8 |
||||||
|
# cp external/SDL2/SDL2/android-project/app/src/main/java/org/libsdl/app/*.java android/app/src/main/java/org/libsdl/app/ |
Binary file not shown.
After Width: | Height: | Size: 9.7 KiB |
@ -0,0 +1,226 @@ |
|||||||
|
#include "audio.h" |
||||||
|
#include <SDL_keycode.h> |
||||||
|
#include <SDL_mixer.h> |
||||||
|
#include <SDL_mutex.h> |
||||||
|
|
||||||
|
void generate_audio(void); |
||||||
|
struct game_sounds game_sounds; |
||||||
|
|
||||||
|
Uint8 big_hum(unsigned int t);
|
||||||
|
Uint8 func0(unsigned int t);
|
||||||
|
|
||||||
|
int mute = false; |
||||||
|
|
||||||
|
void fill_audio(void *func, Uint8 *stream, int len) { |
||||||
|
Uint8 (*wavegen)(unsigned int) = func; |
||||||
|
|
||||||
|
unsigned int t = 1; |
||||||
|
for(int i = 0; i < len; i++,t++) { |
||||||
|
stream[i] = wavegen(t); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void callbackfn3(void *unused, Uint8 *stream, int len) { |
||||||
|
static int t = 1; |
||||||
|
for(int i = 0; i < len; i++,t++) { |
||||||
|
stream[i] = big_hum(t); |
||||||
|
stream[i] = 0;
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void start_audio(void) { |
||||||
|
|
||||||
|
//audio_format.callback = callbackfn3;
|
||||||
|
/* just for playing background music
|
||||||
|
if (SDL_OpenAudio(&audio_format, NULL)) { |
||||||
|
fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError()); |
||||||
|
exit(1); |
||||||
|
} |
||||||
|
*/ |
||||||
|
//SDL_PauseAudio(0);
|
||||||
|
if (Mix_OpenAudio(G_AUDIO_SFREQ,AUDIO_U8,1,G_AUDIO_BSIZE) < 0) { |
||||||
|
fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError()); |
||||||
|
exit(1); |
||||||
|
} |
||||||
|
|
||||||
|
if (Mix_AllocateChannels(20) < 0) { |
||||||
|
fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError()); |
||||||
|
} |
||||||
|
|
||||||
|
generate_audio(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void
|
||||||
|
play_game_sound(Mix_Chunk *chunk, int len, int channel)
|
||||||
|
{ |
||||||
|
if (mute || Mix_Playing(channel)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if(Mix_PlayChannelTimed(channel, chunk, -1, len) < 0) |
||||||
|
fprintf(stderr, "Unable to play audio: %s\n", SDL_GetError()); |
||||||
|
//Mix_FadeInChannelTimed(channel, chunk, -1, 1, len);
|
||||||
|
} |
||||||
|
|
||||||
|
Uint8
|
||||||
|
pitchshift_hit(unsigned int t, void *arg)
|
||||||
|
{ |
||||||
|
double *hitt = arg; |
||||||
|
double hit = *hitt; |
||||||
|
hit = 6 - hit; |
||||||
|
int lower = 10 + 2 * (hit > 6 ? 6 : hit); |
||||||
|
int higher = 1 + (hit > 6 ? 6 : hit); |
||||||
|
// printf("mag %f higher %d lower %d\n", hit, higher, lower);
|
||||||
|
|
||||||
|
const double R=8000; // sample rate (samples per second)
|
||||||
|
const double C=125; // frequency of middle-C (hertz)
|
||||||
|
const double F=R/256; // bytebeat frequency of 1*t due to 8-bit truncation (hertz)
|
||||||
|
const double V=127; // a volume constant
|
||||||
|
double volume = (((t / 3000) > 2) ? 2 : t / 3000); |
||||||
|
|
||||||
|
return ((sin(t*2*M_PI/R*(125 + hit))+1)*10 + (sin(t*2*M_PI/R*(250 + hit))+1)*(50 + hit) + (sin(t*2*M_PI/R*(900 + hit))+1)*100 + (sin(t*2*M_PI/R*(150+ hit))+1)*5) ; |
||||||
|
|
||||||
|
return ((t < 3000) * ((t % higher) * (3000 - t % 3000) * 0.00351)); |
||||||
|
//+ ((t < 3500) * ((3500 - t % 3500)) * 0.0002 * (t % lower));
|
||||||
|
} |
||||||
|
|
||||||
|
void
|
||||||
|
synthplay_now(Uint8 (*bbgen)(unsigned int t, void *), void *arg, int len)
|
||||||
|
{ |
||||||
|
static Mix_Chunk *new_chunk = NULL; |
||||||
|
|
||||||
|
if (Mix_Playing(1)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (new_chunk) |
||||||
|
Mix_FreeChunk(new_chunk); |
||||||
|
|
||||||
|
int generate_len = len * (512); |
||||||
|
|
||||||
|
Uint8 raw_data[generate_len]; |
||||||
|
|
||||||
|
unsigned int t = 1; |
||||||
|
for(int i = 0; i < generate_len; i++,t++) { |
||||||
|
raw_data[i] = bbgen(t, arg); |
||||||
|
} |
||||||
|
|
||||||
|
new_chunk = Mix_QuickLoad_RAW(raw_data, generate_len); |
||||||
|
Mix_PlayChannelTimed(1, new_chunk, -1, len); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void callbackfn2(void *unused, Uint8 *stream, int len) { |
||||||
|
static int t = 1; |
||||||
|
int i; |
||||||
|
int yeet = rand(); |
||||||
|
for(i=0; i < len; i++,t++) { |
||||||
|
stream[i] = func0(t); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void callbackfn(void *unused, Uint8 *stream, int len) |
||||||
|
{ |
||||||
|
static int t = 0; |
||||||
|
int i; |
||||||
|
int yeet = rand(); |
||||||
|
for( i=0; i < len; i++,t++) { |
||||||
|
/*
|
||||||
|
stream[i] = (t*5&(t>>7))|(t*3&(t>>8)); |
||||||
|
*/ |
||||||
|
//stream[i] = (( t >> 10 ) & 42) * t;
|
||||||
|
stream[i] = (t & yeet) % 73; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* Waveform Generators */ |
||||||
|
|
||||||
|
Uint8 big_hum(unsigned int t) { |
||||||
|
return ( (sin(t*2*3.14159265/8000*200)+1) * 20) + ( (sin(t*2*3.14159265/8000*110)+1) * 20) + ( (sin(t*2*3.14159265/8000*230)+1) * 20) + ( (sin((t % 80)*2*3.14159265/8000 * 6)+1) * 12); |
||||||
|
} |
||||||
|
|
||||||
|
unsigned int sine_wave_sound(unsigned int t) { |
||||||
|
const double R=8000; // sample rate (samples per second)
|
||||||
|
const double C=261.625565; // frequency of middle-C (hertz)
|
||||||
|
const double F=R/256; // bytebeat frequency of 1*t due to 8-bit truncation (hertz)
|
||||||
|
const double V=127; // a volume constant
|
||||||
|
return (sin(t*2*M_PI/R*C)+1)*V; |
||||||
|
} |
||||||
|
|
||||||
|
Uint8 winch_sound(unsigned t) { |
||||||
|
return (((t % 80) | (t % 36) | (6 * (t % 6))) + 20) * 1.6; |
||||||
|
return ((t % 80) | (t % 36) | (6 * (t % 6))); |
||||||
|
} |
||||||
|
|
||||||
|
Uint8 beat_2(unsigned t) { |
||||||
|
return ((((t % 250) / 2)) | (t % 129)) % 110; |
||||||
|
} |
||||||
|
|
||||||
|
Uint8 func0(unsigned t) { |
||||||
|
int note = 18; |
||||||
|
if (!(t % 1240)) { |
||||||
|
note = (1 + rand()) % 18 + 1; |
||||||
|
} |
||||||
|
|
||||||
|
fflush(stdout); |
||||||
|
return (t % note); |
||||||
|
} |
||||||
|
|
||||||
|
Uint8 func1(unsigned int t) { |
||||||
|
int note = 10; |
||||||
|
if (!(t % 8000)) { |
||||||
|
note = (1 + rand()) % 10 + 5; |
||||||
|
} |
||||||
|
return ((t & 110) % 73 | (t % 1711)); |
||||||
|
} |
||||||
|
|
||||||
|
Uint8 collision_test(unsigned int t) { |
||||||
|
// try not to loop
|
||||||
|
return ((t < 3000) * ((t % 5) * (3000 - t % 3000) * 0.00351))
|
||||||
|
+ ((t < 3500) * ((3500 - t % 3500)) * 0.0002 * (t % 14)); |
||||||
|
return ((t < 3000) * ((t % 5) * (3000 - t % 3000) * 0.00351))
|
||||||
|
+ ((4000 - t % 4000) * 0.0003 * (t % 128))
|
||||||
|
+ ((t < 3500) * ((3500 - t % 3500)) * 0.0002 * (t % 64)); // has a big low sound
|
||||||
|
return (t % 4) * (4000 - t % 4000) * 0.01; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
Uint8 boop_noise(unsigned int t) { |
||||||
|
return ((t >> 10) & 42) * t; |
||||||
|
} |
||||||
|
|
||||||
|
Uint8 rope_attach(unsigned int t) { |
||||||
|
return (((2000 - (t % 2000)))/40 * (t % 20) | (t % 44) + 20) * 1.6; |
||||||
|
} |
||||||
|
|
||||||
|
void generate_audio(void) { |
||||||
|
const int sfx_len_ms = 1000; |
||||||
|
unsigned int sfx_len = (G_AUDIO_SFREQ/1000) * G_AUDIO_BSIZE * sfx_len_ms; |
||||||
|
sfx_len = G_AUDIO_BSIZE; |
||||||
|
|
||||||
|
Uint8 *raw_data = malloc(sfx_len);
|
||||||
|
fill_audio(winch_sound, raw_data, sfx_len); |
||||||
|
game_sounds.rope_pull = Mix_QuickLoad_RAW(raw_data, sfx_len); |
||||||
|
Mix_Volume(BC_ROPE_PULL, MIX_MAX_VOLUME * 0.3); |
||||||
|
|
||||||
|
Uint8 *raw_data2 = malloc(sfx_len);
|
||||||
|
fill_audio(collision_test, raw_data2, sfx_len); |
||||||
|
game_sounds.collision = Mix_QuickLoad_RAW(raw_data2, sfx_len); |
||||||
|
Mix_Volume(BC_COLLISION, MIX_MAX_VOLUME * 1.2); |
||||||
|
|
||||||
|
Uint8 *raw_data3 = malloc(sfx_len);
|
||||||
|
fill_audio(big_hum, raw_data3, sfx_len); |
||||||
|
game_sounds.background = Mix_QuickLoad_RAW(raw_data3, sfx_len); |
||||||
|
Mix_Volume(BC_MUSIC, MIX_MAX_VOLUME * 0.1); |
||||||
|
|
||||||
|
Uint8 *raw_data4 = malloc(sfx_len);
|
||||||
|
fill_audio(rope_attach, raw_data4, sfx_len); |
||||||
|
game_sounds.rope_attach = Mix_QuickLoad_RAW(raw_data4, sfx_len); |
||||||
|
Mix_Volume(BC_ROPE_ATTACH, MIX_MAX_VOLUME * 0.1); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
@ -0,0 +1,37 @@ |
|||||||
|
|
||||||
|
#ifndef AUDIO_H |
||||||
|
#define AUDIO_H |
||||||
|
|
||||||
|
#include <SDL_audio.h> |
||||||
|
#include "types.h" |
||||||
|
#include <math.h> |
||||||
|
#include <stdlib.h> |
||||||
|
|
||||||
|
#define G_AUDIO_SFREQ 8000 |
||||||
|
#define G_AUDIO_BSIZE 512 |
||||||
|
|
||||||
|
struct game_sounds { |
||||||
|
unsigned int t; |
||||||
|
Mix_Chunk *collision; |
||||||
|
Mix_Chunk *rope_attach; |
||||||
|
Mix_Chunk *rope_pull; |
||||||
|
Mix_Chunk *background; |
||||||
|
/* Looping samples (need backbuffer to fill while playing ) */ |
||||||
|
Mix_Chunk *menu; |
||||||
|
}; |
||||||
|
|
||||||
|
extern struct game_sounds game_sounds; |
||||||
|
|
||||||
|
void play_game_sound(Mix_Chunk *chunk, int len, int channel); |
||||||
|
void start_audio(void);
|
||||||
|
|
||||||
|
Uint8 pitchshift_hit(unsigned int t, void *arg); |
||||||
|
void synthplay_now(Uint8 (*bbgen)(unsigned int t, void *), void *arg, int len);
|
||||||
|
|
||||||
|
enum audio_channel_names { |
||||||
|
BC_COLLISION = 1, |
||||||
|
BC_ROPE_PULL = 2, |
||||||
|
BC_ROPE_ATTACH = 3, |
||||||
|
BC_MUSIC = 4, |
||||||
|
}; |
||||||
|
#endif |
@ -0,0 +1,97 @@ |
|||||||
|
#include <stdio.h> |
||||||
|
#include <time.h> |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
// #define LOGGING 1
|
||||||
|
// #define log_var(string, content) if (LOGGING) {time_t current_time; time(¤t_time); printf("%s",asctime(localtime(¤t_time))); printf(string, content);}
|
||||||
|
// #define log_str(string) if (LOGGING) {time_t current_time; time(¤t_time); puts(asctime(localtime(¤t_time))); puts(string);}
|
||||||
|
|
||||||
|
void enumerate_string(char test_array[]) { |
||||||
|
char *ptr; |
||||||
|
ptr = &(test_array[0]); |
||||||
|
for (int i=0; i<5; i++) { |
||||||
|
printf("%c", *(ptr + i)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int copy_str(char * out_string, char * string) { |
||||||
|
/* A drop in replacement for strcpy() from <string.h>*/ |
||||||
|
int len = 0; |
||||||
|
while (*(string + len) != '\0') { |
||||||
|
*(out_string + len) = *(string + len); |
||||||
|
len++; |
||||||
|
} |
||||||
|
*(out_string + len) = '\0'; |
||||||
|
return (1); |
||||||
|
} |
||||||
|
|
||||||
|
int get_str_len(char * string) { |
||||||
|
int len = 0; |
||||||
|
while (*(string + len) != '\0') { |
||||||
|
len++; |
||||||
|
} |
||||||
|
return(len); |
||||||
|
} |
||||||
|
|
||||||
|
void replace_char(char * array, char * charac) { |
||||||
|
int length; |
||||||
|
length = sizeof(*array)/sizeof(char); |
||||||
|
char combined[length]; |
||||||
|
|
||||||
|
int i = 0; |
||||||
|
int counter = 0; |
||||||
|
|
||||||
|
while (*(array + i) != '\0') { |
||||||
|
if (*(array + i) != *charac) { |
||||||
|
*(array + counter) = *(array + i); |
||||||
|
counter++; |
||||||
|
} |
||||||
|
i++; |
||||||
|
} |
||||||
|
*(array + counter + 1) = '\0'; |
||||||
|
} |
||||||
|
|
||||||
|
void join_strings(char * return_val, char * str_1, char * str_2) { |
||||||
|
|
||||||
|
int len1 = get_str_len(str_1); |
||||||
|
int len2 = get_str_len(str_2); |
||||||
|
|
||||||
|
int length = len1 + len2; |
||||||
|
char combined[length+1]; |
||||||
|
int i = 0; |
||||||
|
int j = 0; |
||||||
|
|
||||||
|
while (*(str_1 + i) != '\0') { |
||||||
|
combined[i] = *(str_1 + i); |
||||||
|
i++; |
||||||
|
} |
||||||
|
|
||||||
|
while (*(str_2 + j) != '\0') { |
||||||
|
combined[len1+j] = *(str_2 + j); |
||||||
|
j++; |
||||||
|
} |
||||||
|
copy_str(return_val, combined); |
||||||
|
} |
||||||
|
|
||||||
|
void get_time(void) { |
||||||
|
char time_str[100]; |
||||||
|
time_t current_time; |
||||||
|
time(¤t_time);
|
||||||
|
copy_str(time_str, asctime(localtime(¤t_time))); |
||||||
|
|
||||||
|
strcat(time_str, "hello world"); |
||||||
|
//replace_char(&(time_str[0]), "\n");
|
||||||
|
printf("%s", time_str); |
||||||
|
|
||||||
|
char string[20]; |
||||||
|
copy_str(string, "NONEWLINEhello"); |
||||||
|
|
||||||
|
|
||||||
|
replace_char(&(time_str[0]), "\n"); |
||||||
|
char newstr[120]; |
||||||
|
join_strings(&(newstr[0]), &(time_str[0]), &(string[0])); |
||||||
|
replace_char(&(newstr[0]), "\n"); |
||||||
|
|
||||||
|
printf("%s", newstr); |
||||||
|
} |
||||||
|
|
@ -0,0 +1,238 @@ |
|||||||
|
#include "colours.h" |
||||||
|
|
||||||
|
struct colour get_random_color(unsigned int seed) { |
||||||
|
srand(seed); |
||||||
|
int red = rand() % 255; |
||||||
|
int blue = rand() % 255; |
||||||
|
int green = rand() % 255; |
||||||
|
|
||||||
|
struct colour col; |
||||||
|
col.r = red; |
||||||
|
col.g = green; |
||||||
|
col.b = blue; |
||||||
|
return col; |
||||||
|
} |
||||||
|
|
||||||
|
double m_min(double arr[], int len) { |
||||||
|
double largest = arr[0]; |
||||||
|
for (int i = 0; i < len; i ++) { |
||||||
|
if (arr[i] < largest) { |
||||||
|
largest = arr[i]; |
||||||
|
} |
||||||
|
} |
||||||
|
return largest; |
||||||
|
} |
||||||
|
|
||||||
|
double m_max(double arr[], int len) { |
||||||
|
double largest = arr[0]; |
||||||
|
for (int i = 0; i < len; i ++) { |
||||||
|
if (arr[i] > largest) { |
||||||
|
largest = arr[i]; |
||||||
|
} |
||||||
|
} |
||||||
|
return largest; |
||||||
|
} |
||||||
|
|
||||||
|
bool m_equal(double a, double b) { |
||||||
|
return (a - b) * (a - b) < 0.00001; |
||||||
|
} |
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB
|
||||||
|
// h = [0,360], s = [0,1], v = [0,1]
|
||||||
|
// if s == 0, then h = -1 (undefined)
|
||||||
|
struct colour get_hs_l_v(struct colour c, enum colour_space sp) { |
||||||
|
struct colour ret; |
||||||
|
memset(&ret, 0, sizeof(struct colour)); |
||||||
|
double r = (double)c.r / 255; |
||||||
|
double g = (double)c.g / 255; |
||||||
|
double b = (double)c.b / 255; |
||||||
|
|
||||||
|
double arr[] = {r, g, b}; |
||||||
|
double max = m_max(arr, 3); |
||||||
|
double min = m_min(arr, 3); |
||||||
|
|
||||||
|
ret.v = max; |
||||||
|
|
||||||
|
double chroma = max - min; |
||||||
|
|
||||||
|
double lum = (max + min) / 2; |
||||||
|
ret.l = lum; |
||||||
|
|
||||||
|
if (m_equal(chroma, 0)) { |
||||||
|
ret.h = 0; |
||||||
|
} else if (m_equal(ret.v,r)) { |
||||||
|
ret.h = (g - b) / chroma; |
||||||
|
} else if (m_equal(max,g)) { |
||||||
|
ret.h = 2 + (b - r) / chroma; |
||||||
|
} else if (m_equal(max,b)) { |
||||||
|
ret.h = 4 + (r - g) / chroma; |
||||||
|
} else { |
||||||
|
printf("NOPE BAD ERROR\n"); |
||||||
|
}
|
||||||
|
|
||||||
|
ret.h *= 60; |
||||||
|
ret.h = fmod(ret.h, 360); |
||||||
|
if (ret.h < 0) { |
||||||
|
ret.h += 360; |
||||||
|
} |
||||||
|
|
||||||
|
if (sp == CS_HSV) { |
||||||
|
if (m_equal(max,0)) { |
||||||
|
ret.s = 0; |
||||||
|
} else { |
||||||
|
ret.s = chroma / max; |
||||||
|
} |
||||||
|
} else { |
||||||
|
double arr[] = {ret.l, 1 - ret.l}; |
||||||
|
if (m_equal(0, lum) || m_equal(1, lum)) { |
||||||
|
ret.s = 0; |
||||||
|
} else { |
||||||
|
ret.s = (ret.v - ret.l) / m_min(arr, 2);
|
||||||
|
} |
||||||
|
} |
||||||
|
ret.sp = CS_HSL; |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
struct colour get_hsl(struct colour c) { |
||||||
|
return get_hs_l_v(c, CS_HSL);
|
||||||
|
} |
||||||
|
|
||||||
|
struct colour get_hsv(struct colour c) { |
||||||
|
return get_hs_l_v(c, CS_HSV);
|
||||||
|
} |
||||||
|
|
||||||
|
double magic_hsv_function(int n, struct colour c) { |
||||||
|
double res = 0; |
||||||
|
double k = fmod(n + (c.h / 60), 6); |
||||||
|
double arr[] = {k, 4 - k, 1}; |
||||||
|
double k_b = m_min(arr, 3); |
||||||
|
double k_c = 0 > k_b ? 0 : k_b; |
||||||
|
res = c.v - c.v * c.s * k_c;
|
||||||
|
return res; |
||||||
|
} |
||||||
|
|
||||||
|
struct colour get_rgb_from_hsv(struct colour c) { |
||||||
|
|
||||||
|
double r = magic_hsv_function(5, c); |
||||||
|
double g = magic_hsv_function(3, c); |
||||||
|
double b = magic_hsv_function(1, c); |
||||||
|
|
||||||
|
struct colour res; |
||||||
|
res.r = round(r * 255); |
||||||
|
res.g = round(g * 255); |
||||||
|
res.b = round(b * 255); |
||||||
|
return res; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
double magic_hsl_function(int n, struct colour c) { |
||||||
|
double arr[] = {c.l, 1-c.l}; |
||||||
|
double a = c.s * ( c.l < (1-c.l) ? c.l : 1 - c.l ); |
||||||
|
double k = fmod(n + c.h / 30, 12); |
||||||
|
|
||||||
|
double b[] = {k - 3, 9 -k, 1}; |
||||||
|
double d[] = {-1, m_min(b, 3)}; |
||||||
|
return c.l - a * (d[0] > d[1] ? d[0] : d[1]); |
||||||
|
} |
||||||
|
|
||||||
|
struct colour get_rgb_from_hsl(struct colour c) { |
||||||
|
double r = magic_hsl_function(0, c); |
||||||
|
double g = magic_hsl_function(8, c); |
||||||
|
double b = magic_hsl_function(4, c); |
||||||
|
|
||||||
|
struct colour res; |
||||||
|
res.r = round(r * 255); |
||||||
|
res.g = round(g * 255); |
||||||
|
res.b = round(b * 255); |
||||||
|
return res; |
||||||
|
} |
||||||
|
|
||||||
|
struct colour get_rgb(struct colour c) { |
||||||
|
if (c.sp == CS_HSL) { |
||||||
|
return get_rgb_from_hsl(c); |
||||||
|
} |
||||||
|
if (c.sp == CS_HSV) { |
||||||
|
return get_rgb_from_hsv(c); |
||||||
|
} |
||||||
|
|
||||||
|
struct colour d; |
||||||
|
memset(&d, 0, sizeof(struct colour)); |
||||||
|
return d; |
||||||
|
} |
||||||
|
|
||||||
|
int compare_perceived_lum(const void* c1, const void* c2) { |
||||||
|
struct colour rgb_c1 = *(struct colour*)c1; |
||||||
|
struct colour rgb_c2 = *(struct colour*)c2; |
||||||
|
|
||||||
|
double lum1 = 0.299*rgb_c1.r + 0.587*rgb_c1.g + 0.114*rgb_c1.b; |
||||||
|
double lum2 = 0.299*rgb_c2.r + 0.587*rgb_c2.g + 0.114*rgb_c2.b; |
||||||
|
return lum1 - lum2; |
||||||
|
} |
||||||
|
|
||||||
|
struct colour *get_adjacent(struct colour base, int deg, int num) { |
||||||
|
struct colour col = get_hsl(base); |
||||||
|
num += 1; |
||||||
|
|
||||||
|
struct colour* colours = calloc(sizeof(struct colour), num);
|
||||||
|
|
||||||
|
for (int i = 0; i < num; i++) { |
||||||
|
int m = (i % 2 == 0) ? -i : i; |
||||||
|
|
||||||
|
colours[i] = col; |
||||||
|
colours[i].h += m * deg; |
||||||
|
colours[i].h += fmod(colours[i].h, 360); |
||||||
|
} |
||||||
|
|
||||||
|
struct colour *ret_colours = calloc(num, sizeof(struct colour) * num); |
||||||
|
|
||||||
|
for (int i = 0; i < num; i++) { |
||||||
|
ret_colours[i] = get_rgb(colours[i]); |
||||||
|
} |
||||||
|
|
||||||
|
// sort from dark to bright
|
||||||
|
qsort(ret_colours, num, sizeof(struct colour), compare_perceived_lum); |
||||||
|
|
||||||
|
free(colours); |
||||||
|
return ret_colours; |
||||||
|
} |
||||||
|
|
||||||
|
void print_colour(struct colour c) { |
||||||
|
char *colour = calloc(20, sizeof(char)); |
||||||
|
sprintf(colour, "#%02x%02x%02x", c.r, c.g, c.b); |
||||||
|
|
||||||
|
printf("\x1b[38;2;%d;%d;%dm%s\x1b[0m\n", c.r, c.g, c.b, colour); |
||||||
|
free(colour); |
||||||
|
} |
||||||
|
|
||||||
|
void test(int seed) { |
||||||
|
struct colour c = get_random_color(seed); |
||||||
|
//print_colour(c);
|
||||||
|
struct colour hsl = get_hsl(c); |
||||||
|
struct colour hsv = get_hsv(c); |
||||||
|
/*printf("RGB: %d %d %d\n",c.r,c.g,c.b);*/ |
||||||
|
/*printf("HSL: %f %f %f\n",hsl.h, hsl.s, hsl.l);*/ |
||||||
|
/*printf("HSV: %f %f %f\n",hsv.h, hsv.s, hsv.v);*/ |
||||||
|
|
||||||
|
struct colour *adj = get_adjacent(c, 5, 4); |
||||||
|
for (int i = 0; i < 5; i++) { |
||||||
|
print_colour(adj[i]); |
||||||
|
} |
||||||
|
|
||||||
|
free(adj); |
||||||
|
printf("\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void test_print_wheel() { |
||||||
|
struct colour c; |
||||||
|
c.s = 0.999; |
||||||
|
c.v = 0.99; |
||||||
|
c.l = 0.5; |
||||||
|
c.sp = CS_HSV; |
||||||
|
for(int i = 0; i < 360; i+=5) { |
||||||
|
c.h = (double)i; |
||||||
|
struct colour rgb = get_rgb(c); |
||||||
|
print_colour(rgb); |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
|
||||||
|
#ifndef COSMOPOLITAN |
||||||
|
#include <stdbool.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
#include <math.h> |
||||||
|
#include <stdio.h> |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifndef H_COLOURS |
||||||
|
#define H_COLOURS |
||||||
|
|
||||||
|
enum colour_space { |
||||||
|
CS_INVALID = 0, |
||||||
|
CS_RGB = 1, // default to RGB
|
||||||
|
CS_HSV = 2, |
||||||
|
CS_HSL = 3, |
||||||
|
}; |
||||||
|
|
||||||
|
struct colour { |
||||||
|
double h; |
||||||
|
double s; |
||||||
|
double v; |
||||||
|
double l; |
||||||
|
int r; |
||||||
|
int g; |
||||||
|
int b; |
||||||
|
enum colour_space sp; |
||||||
|
}; |
||||||
|
|
||||||
|
struct colour get_random_color(unsigned int seed); |
||||||
|
|
||||||
|
// doesn't support hsl-hsv or converse, conversion
|
||||||
|
struct colour get_hsl(struct colour c); |
||||||
|
struct colour get_hsv(struct colour c);
|
||||||
|
|
||||||
|
struct colour get_rgb(struct colour c);
|
||||||
|
|
||||||
|
struct colour *get_adjacent(struct colour base, int deg, int num);
|
||||||
|
|
||||||
|
void print_colour(struct colour c);
|
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,106 @@ |
|||||||
|
|
||||||
|
#include "controlscheme.h" |
||||||
|
#include <SDL_scancode.h> |
||||||
|
|
||||||
|
#ifdef LOAD_INPUTS |
||||||
|
#include <sys/stat.h> |
||||||
|
#endif |
||||||
|
|
||||||
|
struct InputMap input_map; |
||||||
|
|
||||||
|
#define INPUT_MAP_ID 83921864 |
||||||
|
#define INPUT_MAP_VERSION 0 |
||||||
|
#define CONTROLS_FNAME "controls.bin" |
||||||
|
|
||||||
|
struct InputMap_Ser { |
||||||
|
unsigned int id; |
||||||
|
unsigned int ver; |
||||||
|
struct InputMap input_map; |
||||||
|
}; |
||||||
|
|
||||||
|
int load_controls(void);
|
||||||
|
|
||||||
|
void get_input_map(void) { |
||||||
|
|
||||||
|
#ifdef LOAD_INPUTS |
||||||
|
if (load_controls()) { |
||||||
|
return; |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
input_map.player_down = SDL_SCANCODE_S; |
||||||
|
input_map.player_up = SDL_SCANCODE_W; |
||||||
|
input_map.player_right = SDL_SCANCODE_D; |
||||||
|
input_map.player_left = SDL_SCANCODE_A; |
||||||
|
input_map.player_rope = SDL_SCANCODE_E; |
||||||
|
input_map.player_pull_rope = SDL_SCANCODE_Q; |
||||||
|
input_map.mute = SDL_SCANCODE_M; |
||||||
|
input_map.pause = SDL_SCANCODE_ESCAPE; |
||||||
|
input_map.quit = SDL_SCANCODE_Q; |
||||||
|
input_map.goto_level = SDL_SCANCODE_G; |
||||||
|
input_map.mouse_attach_rope_pull = SDL_BUTTON_LEFT; |
||||||
|
input_map.mouse_attach_rope = SDL_BUTTON_RIGHT; |
||||||
|
} |
||||||
|
|
||||||
|
#ifdef LOAD_INPUTS |
||||||
|
struct Buffer { |
||||||
|
size_t len; |
||||||
|
char *data; |
||||||
|
}; |
||||||
|
|
||||||
|
struct Buffer read_whole_file(char const *file_name) { |
||||||
|
struct stat sb; |
||||||
|
struct Buffer b = {}; |
||||||
|
|
||||||
|
if (stat (file_name, & sb) != 0) { |
||||||
|
return b; |
||||||
|
} |
||||||
|
|
||||||
|
char *buffer = malloc(sb.st_size + 1); |
||||||
|
|
||||||
|
FILE *f = fopen(file_name, "r"); |
||||||
|
size_t bytes_read = fread(buffer, sizeof (unsigned char), sb.st_size, f); |
||||||
|
if (bytes_read != sb.st_size) { |
||||||
|
fclose(f); |
||||||
|
free(buffer); |
||||||
|
return b; |
||||||
|
} |
||||||
|
|
||||||
|
fclose(f); |
||||||
|
|
||||||
|
b.data = buffer; |
||||||
|
b.len = bytes_read; |
||||||
|
return b; |
||||||
|
} |
||||||
|
|
||||||
|
int load_controls(void) { |
||||||
|
struct Buffer b = read_whole_file(CONTROLS_FNAME); |
||||||
|
|
||||||
|
if (b.len != sizeof (struct InputMap_Ser)) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
struct InputMap_Ser *im = (struct InputMap_Ser *)b.data; |
||||||
|
|
||||||
|
if (im->id != INPUT_MAP_ID) |
||||||
|
return 0; |
||||||
|
|
||||||
|
if (im->ver != INPUT_MAP_VERSION) |
||||||
|
return 0; |
||||||
|
|
||||||
|
memcpy(&input_map, &im->input_map, sizeof(struct InputMap)); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
void save_controls(void) { |
||||||
|
FILE *f = fopen(CONTROLS_FNAME, "w"); |
||||||
|
|
||||||
|
struct InputMap_Ser im; |
||||||
|
im.id = INPUT_MAP_ID; |
||||||
|
im.ver = INPUT_MAP_VERSION; |
||||||
|
im.input_map = input_map; |
||||||
|
|
||||||
|
fwrite(&im, sizeof(unsigned char), sizeof(struct InputMap_Ser), f); |
||||||
|
fclose(f); |
||||||
|
} |
||||||
|
#endif |
@ -0,0 +1,35 @@ |
|||||||
|
#include <SDL.h> |
||||||
|
|
||||||
|
#ifndef CRTL_H |
||||||
|
#define CRTL_H |
||||||
|
|
||||||
|
enum Game_Interaction { |
||||||
|
PLAYER_UP, |
||||||
|
PLAYER_DOWN, |
||||||
|
PLAYER_RIGHT, |
||||||
|
PLAYER_LEFT |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
struct InputMap {
|
||||||
|
SDL_Scancode player_up; |
||||||
|
SDL_Scancode player_down; |
||||||
|
SDL_Scancode player_left; |
||||||
|
SDL_Scancode player_right; |
||||||
|
SDL_Scancode player_rope; |
||||||
|
SDL_Scancode player_pull_rope; |
||||||
|
SDL_Scancode mute; |
||||||
|
SDL_Scancode quit; |
||||||
|
SDL_Scancode pause; |
||||||
|
SDL_Scancode goto_level; |
||||||
|
Uint8 mouse_attach_rope_pull; |
||||||
|
Uint8 mouse_attach_rope; |
||||||
|
}; |
||||||
|
|
||||||
|
extern struct InputMap input_map; |
||||||
|
|
||||||
|
void get_input_map(void);
|
||||||
|
void save_controls(void);
|
||||||
|
|
||||||
|
#endif |
||||||
|
|
@ -0,0 +1,159 @@ |
|||||||
|
#include "datatypes.h" |
||||||
|
#include <string.h> |
||||||
|
#include <stdlib.h> |
||||||
|
|
||||||
|
ArrayList new_arlst(int num_elems) { |
||||||
|
ArrayList new_list; |
||||||
|
new_list.free = NULL; |
||||||
|
new_list.size = 0; |
||||||
|
new_list.capacity = num_elems; |
||||||
|
new_list.items = calloc(num_elems, sizeof(void *)); |
||||||
|
|
||||||
|
return new_list; |
||||||
|
} |
||||||
|
|
||||||
|
ArrayList new_arlst_wfree(int num_elems, void (*nfree)(void *ptr)) { |
||||||
|
ArrayList new_list = new_arlst(num_elems); |
||||||
|
new_list.free = nfree; |
||||||
|
return new_list; |
||||||
|
} |
||||||
|
|
||||||
|
ArrayList new_arlst_using_array(void **array, int length) { |
||||||
|
ArrayList l = new_arlst(length); |
||||||
|
free(l.items); |
||||||
|
l.items = array; |
||||||
|
return l; |
||||||
|
} |
||||||
|
|
||||||
|
ArrayList new_arlst_using_array_wfree(void **array, int length,
|
||||||
|
void (*f)(void *)) { |
||||||
|
ArrayList l = new_arlst_using_array(array, length); |
||||||
|
l.free = f; |
||||||
|
return l; |
||||||
|
} |
||||||
|
|
||||||
|
ArrayList new_arlst_from_array(void *array, size_t elem_size, int length) { |
||||||
|
ArrayList l = new_arlst(length); |
||||||
|
l.free = free; |
||||||
|
|
||||||
|
for (int i = 0; i < length; i++) { |
||||||
|
void *item = calloc(1, elem_size); |
||||||
|
void *start = array + i * elem_size; |
||||||
|
memmove(item, start, elem_size); |
||||||
|
arlst_add(&l, item); |
||||||
|
} |
||||||
|
return l; |
||||||
|
} |
||||||
|
|
||||||
|
void *arlst_get(ArrayList *l, int id) { |
||||||
|
// out of bounds
|
||||||
|
if (id < 0 || id >= l->size) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
return l->items[id]; |
||||||
|
} |
||||||
|
|
||||||
|
void * arlst_del(ArrayList *l, int id) { |
||||||
|
void *item = arlst_get(l, id); |
||||||
|
|
||||||
|
if (!item) { |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
l->size--; |
||||||
|
// move elements backward
|
||||||
|
for (int i = id; i < l->size; i++) { |
||||||
|
l->items[i] = l->items[i+1]; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// shrink capacity if neccessary
|
||||||
|
if (D_SHRINK_THRESHOLD != 0
|
||||||
|
|| l->size < (100 / D_SHRINK_THRESHOLD) * l->capacity) { |
||||||
|
|
||||||
|
size_t new_size = l-> size + (l->capacity * (100 / D_SHRINK_THRESHOLD) *
|
||||||
|
100 / D_GROW_AMOUNT); |
||||||
|
|
||||||
|
// l->items = reallocarray(l->items, new_size, sizeof(void *));
|
||||||
|
l->items = realloc(l->items, new_size * sizeof(void *)); |
||||||
|
} |
||||||
|
|
||||||
|
return item; |
||||||
|
} |
||||||
|
|
||||||
|
int arlst_add(ArrayList *l, void *item) { |
||||||
|
int item_index = l->size; |
||||||
|
|
||||||
|
// grow if neccessary
|
||||||
|
if (l->size == l->capacity) { |
||||||
|
size_t new_size = l->capacity + (100 / D_GROW_AMOUNT) * l->capacity; |
||||||
|
l->capacity = new_size; |
||||||
|
//l->items = (void **)reallocarray(l->items, new_size, sizeof(void *));
|
||||||
|
l->items = (void **)realloc(l->items, new_size * sizeof(void *)); |
||||||
|
} |
||||||
|
|
||||||
|
l->items[item_index] = item; |
||||||
|
l->size++; |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
void * arlst_pop(ArrayList *l) { |
||||||
|
l->size--; |
||||||
|
return l->items[l->size]; |
||||||
|
} |
||||||
|
|
||||||
|
int arlst_push(ArrayList *l, void *item) { |
||||||
|
return arlst_add(l, item); |
||||||
|
} |
||||||
|
|
||||||
|
int arlst_destroy(ArrayList *l) { |
||||||
|
if (l->free != NULL) { |
||||||
|
for (int i = 0; i < l->size; i++) { |
||||||
|
l->free(l->items[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
free(l->items); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
ListFiFo new_fifo(int start_size) { |
||||||
|
ListFiFo l; |
||||||
|
memset(&l, 0, sizeof(ListFiFo)); |
||||||
|
l.inner = new_arlst(start_size); |
||||||
|
l.size = &l.inner.size; |
||||||
|
return l; |
||||||
|
} |
||||||
|
|
||||||
|
void *fifo_get(ListFiFo *l) { |
||||||
|
if (l->fifo_head >= l->inner.size) { |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
void *value = arlst_get(&l->inner, l->fifo_head); |
||||||
|
|
||||||
|
if (value != NULL) { |
||||||
|
l->fifo_head++; |
||||||
|
} |
||||||
|
|
||||||
|
if (l->fifo_head == l->inner.capacity |
||||||
|
|| (l->fifo_head == l->inner.size
|
||||||
|
&& l->inner.size >= D_MAX_QUEUE_LEN)) { |
||||||
|
// start rewriting from the beginning
|
||||||
|
l->inner.size = 0; |
||||||
|
l->fifo_head = 0; |
||||||
|
// memset(l->inner.items, 0, sizeof(void *) * l->inner.capacity);
|
||||||
|
} |
||||||
|
return value; |
||||||
|
} |
||||||
|
|
||||||
|
/* It is up to the caller to free any data stored */ |
||||||
|
int fifo_add(ListFiFo *l, void *i) { |
||||||
|
if (l->inner.size >= D_MAX_QUEUE_LEN) { |
||||||
|
return -1; |
||||||
|
} |
||||||
|
return arlst_add(&l->inner, i); |
||||||
|
} |
||||||
|
|
@ -0,0 +1,61 @@ |
|||||||
|
#ifndef DTYPE_H |
||||||
|
#define DTYPE_H |
||||||
|
|
||||||
|
#include <stdlib.h> |
||||||
|
|
||||||
|
enum { |
||||||
|
D_SHRINK_THRESHOLD = 50, // percentage of capacity
|
||||||
|
// 0 = never shrink
|
||||||
|
// 100 = always shrink
|
||||||
|
D_GROW_AMOUNT = 50, // percentage of size
|
||||||
|
// 0 = 1 = grow by 1 on every add
|
||||||
|
// 100 = double size whenever space runs out
|
||||||
|
D_MAX_QUEUE_LEN = 400 // maximum num of items allowed in a fifo
|
||||||
|
}; |
||||||
|
|
||||||
|
struct array_list { |
||||||
|
size_t size; |
||||||
|
size_t capacity; |
||||||
|
|
||||||
|
void **items; |
||||||
|
void (*free)(void *ptr); // free function
|
||||||
|
}; |
||||||
|
|
||||||
|
struct list_fifo { |
||||||
|
struct array_list inner; |
||||||
|
size_t fifo_head; |
||||||
|
size_t *size; |
||||||
|
}; |
||||||
|
|
||||||
|
typedef struct array_list ArrayList; |
||||||
|
typedef struct list_fifo ListFiFo; |
||||||
|
|
||||||
|
/* FIFOs */ |
||||||
|
|
||||||
|
ListFiFo new_fifo(int start_size);
|
||||||
|
int fifo_add(ListFiFo *l, void *i);
|
||||||
|
void *fifo_get(ListFiFo *l);
|
||||||
|
|
||||||
|
/* Stacks */ |
||||||
|
|
||||||
|
int arlst_push(ArrayList *l, void *item);
|
||||||
|
void * arlst_pop(ArrayList *l);
|
||||||
|
|
||||||
|
/* Array Lists */ |
||||||
|
|
||||||
|
// constructors
|
||||||
|
ArrayList new_arlst_from_array(void *array, size_t elem_size, int length); |
||||||
|
ArrayList new_arlst_using_array_wfree(void **, int, void (*)(void *));
|
||||||
|
ArrayList new_arlst_using_array(void **array, int length);
|
||||||
|
ArrayList new_arlst_wfree(int num_elems, void (*nfree)(void *ptr));
|
||||||
|
ArrayList new_arlst(int num_elems);
|
||||||
|
|
||||||
|
// destructors
|
||||||
|
int arlst_destroy(ArrayList *l);
|
||||||
|
void * arlst_del(ArrayList *l, int id); |
||||||
|
|
||||||
|
// functions
|
||||||
|
int arlst_add(ArrayList *l, void *item);
|
||||||
|
void *arlst_get(ArrayList *l, int id); |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,881 @@ |
|||||||
|
#include "draw.h" |
||||||
|
#include "game.h" |
||||||
|
#include "types.h" |
||||||
|
#include <SDL_mutex.h> |
||||||
|
#include <SDL_render.h> |
||||||
|
#include <time.h> |
||||||
|
|
||||||
|
Vect viewport_pos; |
||||||
|
int width, height; |
||||||
|
|
||||||
|
bool high_contrast_mode = 0; |
||||||
|
|
||||||
|
/* generic rendering functions */ |
||||||
|
int MAX_ONSCREEN_OBJECTS = 99; |
||||||
|
|
||||||
|
int num_onscreen = 0; |
||||||
|
|
||||||
|
double time_delta = 0; |
||||||
|
|
||||||
|
void render_texture_at(struct SDL_Renderer * ren, struct SDL_Texture * texture,int x, int y) { |
||||||
|
/* draw a texture at x.y */ |
||||||
|
|
||||||
|
SDL_Rect destination; |
||||||
|
destination.x = x; |
||||||
|
destination.y = y; |
||||||
|
|
||||||
|
SDL_QueryTexture(texture, NULL, NULL, &destination.w, &destination.h); |
||||||
|
|
||||||
|
SDL_RenderCopy(ren, texture, NULL, &destination); |
||||||
|
} |
||||||
|
|
||||||
|
/*SDL_Texture * load_image(SDL_Renderer * ren, char fname[]) {*/ |
||||||
|
/*[> Load an image into a texture <]*/ |
||||||
|
|
||||||
|
/*SDL_Surface * surface = IMG_Load(fname) ;*/ |
||||||
|
/*if(!surface) {*/ |
||||||
|
/*printf("IMG_Load: %s\n", IMG_GetError());*/ |
||||||
|
/*// handle error*/ |
||||||
|
/*}*/ |
||||||
|
|
||||||
|
/*SDL_Texture * png_image = SDL_CreateTextureFromSurface(ren, surface);*/ |
||||||
|
/*cleanup(surface, SURFACE);*/ |
||||||
|
/*return (png_image);*/ |
||||||
|
/*}*/ |
||||||
|
|
||||||
|
|
||||||
|
double sigmoid(double x) { |
||||||
|
return exp(x) / (exp(x) + 1); |
||||||
|
} |
||||||
|
|
||||||
|
struct timespec get_now_d() { |
||||||
|
struct timespec now; |
||||||
|
clock_gettime(CLOCK_MONOTONIC, &now); |
||||||
|
if (now.tv_nsec >= 1000000000) { |
||||||
|
now.tv_nsec -= 1000000000; |
||||||
|
} |
||||||
|
return now; |
||||||
|
} |
||||||
|
|
||||||
|
Vect in_view(Vect V) { |
||||||
|
Vect ret; |
||||||
|
ret.x = V.x -viewport_pos.x; |
||||||
|
ret.y = V.y -viewport_pos.y; |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/* Game Specific rendering functions */ |
||||||
|
void draw_player(SDL_Renderer * ren, int x, int y, bool red) { |
||||||
|
// translate to viewport
|
||||||
|
|
||||||
|
Vect V; |
||||||
|
V.x = x; V.y = y; |
||||||
|
V = in_view(V); |
||||||
|
|
||||||
|
/* draw the player as a coloured rect */ |
||||||
|
SDL_Rect player_rect; |
||||||
|
|
||||||
|
player_rect.x = V.x -10;
|
||||||
|
player_rect.y = V.y -10;
|
||||||
|
|
||||||
|
player_rect.w = 20; |
||||||
|
player_rect.h = 20; |
||||||
|
|
||||||
|
struct colour c = get_scene_watch()->colours.bg; |
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(ren, c.r, c.g, c.b, 255); |
||||||
|
|
||||||
|
SDL_RenderDrawRect(ren, &player_rect); |
||||||
|
SDL_RenderFillRect(ren, &player_rect); |
||||||
|
// draw strings
|
||||||
|
for (int i = 0; i < player.physics->num_strings; i++) { |
||||||
|
if (!player.physics->strings[i].attached) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
Vect B = {x, y}; |
||||||
|
B = in_view(B); |
||||||
|
Vect E; |
||||||
|
E = in_view(player.physics->strings[i].end_point); |
||||||
|
SDL_RenderDrawLine(ren, B.x, B.y, E.x, E.y); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(ren, 0,0,0, 255); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void draw_floor(SDL_Renderer *ren, FloorPoly *poly, bool down) { |
||||||
|
SDL_Point left; |
||||||
|
SDL_Point right; |
||||||
|
left.x = poly->left.x - viewport_pos.x; |
||||||
|
|
||||||
|
if (left.x > width) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
right.x = poly->right.x - viewport_pos.x; |
||||||
|
if (right.x < 0) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
left.y = poly->left.y - viewport_pos.y; |
||||||
|
right.y = poly->right.y - viewport_pos.y; |
||||||
|
|
||||||
|
if (left.y <= 0 && right.y <= 0) { |
||||||
|
return; |
||||||
|
} |
||||||
|
if (left.y >= height && right.y >= height) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(ren, 100,100,100, 255); |
||||||
|
|
||||||
|
int end = down ? height : 0; |
||||||
|
|
||||||
|
double m = (double)(right.y - left.y) / (double)(right.x - left.x); |
||||||
|
double c = (double)left.y - ((double)left.x * m); |
||||||
|
|
||||||
|
for (int i = left.x; i <= right.x; i++) { |
||||||
|
int y = (int)(m * i + c); |
||||||
|
if (y > 0) { |
||||||
|
SDL_RenderDrawLine(ren, i, y, i, end); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(ren, 0,0,0, 255); |
||||||
|
} |
||||||
|
|
||||||
|
// draw collision poly
|
||||||
|
void draw_collision_poly(SDL_Renderer* ren, Body *body) { |
||||||
|
if (!SHOWCOLLISION) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (body->colliding) { |
||||||
|
SDL_SetRenderDrawColor(ren, 255, 0, 0, 255); |
||||||
|
} else { |
||||||
|
SDL_SetRenderDrawColor(ren, 0, 255, 0, 255); |
||||||
|
} |
||||||
|
|
||||||
|
// draw strings
|
||||||
|
for (int i = 0; i < body->num_strings; i++) { |
||||||
|
if (!body->strings[i].attached) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
Vect B; |
||||||
|
B = in_view(body->position); |
||||||
|
Vect E; |
||||||
|
E = in_view(body->strings[i].end_point); |
||||||
|
SDL_RenderDrawLine(ren, B.x, B.y, E.x, E.y); |
||||||
|
} |
||||||
|
|
||||||
|
if (body->collision_poly_size == 1) { |
||||||
|
SDL_Rect dot; |
||||||
|
Vect V; |
||||||
|
V.x = body->collision_poly[0].x; |
||||||
|
V.y = body->collision_poly[0].y; |
||||||
|
Vect T = in_view(V); |
||||||
|
dot.x = T.x; |
||||||
|
dot.y = T.y; |
||||||
|
dot.w = 4; |
||||||
|
dot.h = 4; |
||||||
|
SDL_RenderDrawRect(ren, &dot); |
||||||
|
SDL_RenderFillRect(ren, &dot); |
||||||
|
} else if (body->collision_poly_size == 2) { |
||||||
|
int x_st = body->collision_poly[0].x -viewport_pos.x; |
||||||
|
int y_st = body->collision_poly[0].y -viewport_pos.y; |
||||||
|
int x_en = body->collision_poly[1].x -viewport_pos.x; |
||||||
|
int y_en = body->collision_poly[1].y -viewport_pos.y; |
||||||
|
SDL_RenderDrawLine(ren, x_st, y_st, x_en, y_en); |
||||||
|
} else if (body->collision_poly_size > 2) { |
||||||
|
int x_st = body->collision_poly[0].x -viewport_pos.x; |
||||||
|
int y_st = body->collision_poly[0].y -viewport_pos.y; |
||||||
|
int x_en, y_en; |
||||||
|
for (int i = 1; i < body->collision_poly_size; i++) { |
||||||
|
x_en = body->collision_poly[i].x -viewport_pos.x; |
||||||
|
y_en = body->collision_poly[i].y -viewport_pos.y; |
||||||
|
SDL_RenderDrawLine(ren, x_st, y_st, x_en, y_en); |
||||||
|
x_st = x_en; |
||||||
|
y_st = y_en; |
||||||
|
} |
||||||
|
x_en = body->collision_poly[0].x-viewport_pos.x; |
||||||
|
y_en = body->collision_poly[0].y-viewport_pos.y; |
||||||
|
SDL_RenderDrawLine(ren, x_st, y_st, x_en, y_en); |
||||||
|
} |
||||||
|
SDL_SetRenderDrawColor(ren, 0,0,0, 255); |
||||||
|
} |
||||||
|
|
||||||
|
// draw indicator of forces acting on an object
|
||||||
|
void draw_forces(SDL_Renderer *ren, Body *body) { |
||||||
|
if (!SHOWFORCES) { |
||||||
|
return; |
||||||
|
} |
||||||
|
Vect start; |
||||||
|
start.x = (int)body->position.x -viewport_pos.x; |
||||||
|
start.y = (int)body->position.y -viewport_pos.y; |
||||||
|
|
||||||
|
Vect F; |
||||||
|
for (int i = 0; i < body->num_motors; i++) { |
||||||
|
if (!get_motor_active(body, i)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
F.x += body->motors[i].x; |
||||||
|
F.y += body->motors[i].y; |
||||||
|
Vect end = vect_add(start, F); |
||||||
|
SDL_SetRenderDrawColor(ren, 255,0,0, 255); |
||||||
|
SDL_RenderDrawLine(ren, start.x, start.y, start.x, end.y); |
||||||
|
SDL_SetRenderDrawColor(ren, 0,0,255, 255); |
||||||
|
SDL_RenderDrawLine(ren, start.x, start.y, end.x, start.y); |
||||||
|
} |
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(ren, 0,0,0, 255); |
||||||
|
} |
||||||
|
|
||||||
|
void draw_wall(SDL_Renderer *ren, Wall *wall) { |
||||||
|
SDL_SetRenderDrawColor(ren, 120, 85, 188, 255); |
||||||
|
int x_st, x_en, y_st, y_en; |
||||||
|
x_st = wall->nodes[0].x + wall->physics->position.x -viewport_pos.x; |
||||||
|
y_st = wall->nodes[0].y + wall->physics->position.y -viewport_pos.y; |
||||||
|
for (int i = 1; i < wall->numNodes; i++) { |
||||||
|
x_en = wall->nodes[i].x + wall->physics->position.x -viewport_pos.x; |
||||||
|
y_en = wall->nodes[i].y + wall->physics->position.y -viewport_pos.y; |
||||||
|
SDL_RenderDrawLine(ren, x_st, y_st, x_en, y_en); |
||||||
|
x_st = x_en; |
||||||
|
y_st = y_en; |
||||||
|
} |
||||||
|
x_en = wall->nodes[0].x + wall->physics->position.x -viewport_pos.x; |
||||||
|
y_en = wall->nodes[0].y + wall->physics->position.y -viewport_pos.y; |
||||||
|
SDL_RenderDrawLine(ren, x_st, y_st, x_en, y_en); |
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(ren, 0,0,0, 255); |
||||||
|
} |
||||||
|
|
||||||
|
int distance_colour(int x, int y, int x2, int y2, int blackpoint) { |
||||||
|
|
||||||
|
int dist = (int) sqrt((x2 - x)*(x2 - x) + (y2 - y)*(y2 - y) ); |
||||||
|
|
||||||
|
if (dist == 0) { |
||||||
|
return 255; |
||||||
|
} |
||||||
|
if (dist > blackpoint) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int frac = blackpoint / dist; |
||||||
|
|
||||||
|
// int frac = 255 * (int) sin((double)dist / blackpoint);
|
||||||
|
if (frac > 255) { |
||||||
|
return 255; |
||||||
|
} |
||||||
|
|
||||||
|
return frac; |
||||||
|
} |
||||||
|
|
||||||
|
void new_update_viewport(Body const * const pl) { |
||||||
|
int const xmargin = 100; // pixels
|
||||||
|
int const ymargin = 100; // pixels
|
||||||
|
int const xmovmagin = width / 4; |
||||||
|
int const ymovmagin = height / 3; |
||||||
|
double const xrange = width - (2 * xmargin); |
||||||
|
double const yrange = height - (2 * ymargin); |
||||||
|
double const x_max = 2; |
||||||
|
double const y_max = 3; |
||||||
|
static Vect target = {}; |
||||||
|
static double dirchange = 0; |
||||||
|
static Vect last_plpos = {}; |
||||||
|
if (last_plpos.x == 0 && last_plpos.y == 0) |
||||||
|
last_plpos = pl->position; |
||||||
|
|
||||||
|
static Vect lmove = {}; |
||||||
|
|
||||||
|
Vect iv = in_view(pl->position); |
||||||
|
|
||||||
|
Vect left_pos = {0, 2 * height / 4}; |
||||||
|
left_pos = vect_add(pl->position, vect_scalar(left_pos, -1)); |
||||||
|
|
||||||
|
Vect right_pos = {7 * (width / 8), 2 * height / 4}; |
||||||
|
right_pos = vect_add(pl->position, vect_scalar(right_pos, -1)); |
||||||
|
|
||||||
|
bool recover = false; |
||||||
|
|
||||||
|
Vect screen_dist = vect_add(in_view(pl->position), vect_scalar(lmove, -1)); |
||||||
|
|
||||||
|
static double swap = 0; |
||||||
|
if (iv.x > width
|
||||||
|
|| (iv.x < 0 |
||||||
|
|| iv.y > height |
||||||
|
|| iv.y < 0))
|
||||||
|
recover = true; |
||||||
|
|
||||||
|
Vect delta = vect_add(vect_scalar(pl->position, -1), last_plpos); |
||||||
|
double dist_change = vect_mag(delta); |
||||||
|
if ((recover) //|| vect_mag((Vect){pl->vel.x, 0}) > 0.4
|
||||||
|
|| (dist_change > width / 100)) { |
||||||
|
if (iv.x < width / 6) { |
||||||
|
target = right_pos; |
||||||
|
} else { |
||||||
|
target = left_pos; |
||||||
|
} |
||||||
|
lmove = target; |
||||||
|
|
||||||
|
last_plpos = pl->position; |
||||||
|
} |
||||||
|
|
||||||
|
if (recover) |
||||||
|
viewport_pos = target; |
||||||
|
// emergency
|
||||||
|
|
||||||
|
/*if (!(iv.x > width / 3 && iv.x < (2 * (width / 3)))) {*/ |
||||||
|
/*if (!(iv.y > height / 3 && iv.y < (2 * (height / 3)))) {*/ |
||||||
|
|
||||||
|
/*if ( true ||*/ |
||||||
|
/*( in_view(pl->position).x > xmargin + xrange */ |
||||||
|
/*|| in_view(pl->position).x < xmargin)*/ |
||||||
|
/*) */ |
||||||
|
|
||||||
|
/*{*/ |
||||||
|
|
||||||
|
|
||||||
|
/*double m = (width / 2) / (2.0 * x_max);*/ |
||||||
|
/*double x = m * v;*/ |
||||||
|
/*target.x = pl->position.x - x;*/ |
||||||
|
|
||||||
|
|
||||||
|
/*}*/ |
||||||
|
|
||||||
|
//target.y = pl->position.y - height/2; // + y;
|
||||||
|
|
||||||
|
/*}*/ |
||||||
|
/*}*/ |
||||||
|
|
||||||
|
double v = pl->vel.x; |
||||||
|
if (v > x_max)
|
||||||
|
v = x_max; |
||||||
|
if (v < -x_max)
|
||||||
|
v = -x_max; |
||||||
|
if (v < 0) |
||||||
|
v = -v; |
||||||
|
|
||||||
|
// move towards target a set proportion
|
||||||
|
Vect urgency = vect_add(target, vect_scalar(pl->position, -1)); |
||||||
|
Vect p = vect_add(target, vect_scalar(viewport_pos, -1)); |
||||||
|
|
||||||
|
double proportion = (sigmoid(time_delta) / 100); |
||||||
|
proportion = 2 * (pl->vel.x * pl->vel.x / (width)); |
||||||
|
proportion = proportion < 0 ? -proportion : proportion; |
||||||
|
|
||||||
|
proportion > 0.4 ? proportion = 0.4 : 0; |
||||||
|
proportion < 0 ? proportion = 0.000001 : 0; |
||||||
|
|
||||||
|
p = vect_scalar(p, proportion); |
||||||
|
viewport_pos = vect_add(viewport_pos, p); |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void update_viewport(Body *pl) { |
||||||
|
float xmargin = 0.5; |
||||||
|
float ymargin = 0.2; |
||||||
|
|
||||||
|
if (pl->position.x - viewport_pos.x > (1-xmargin) * width) { |
||||||
|
viewport_pos.x = - ((1-xmargin) * width - pl->position.x); |
||||||
|
} |
||||||
|
|
||||||
|
if (pl->position.x - viewport_pos.x < xmargin * width) { |
||||||
|
viewport_pos.x = -(xmargin * width - pl->position.x); |
||||||
|
} |
||||||
|
|
||||||
|
if (pl->position.y - viewport_pos.y > (1-ymargin) * height) { |
||||||
|
viewport_pos.y = -((1-ymargin) * height - pl->position.y); |
||||||
|
} |
||||||
|
|
||||||
|
if (pl->position.y - viewport_pos.y < ymargin * height) { |
||||||
|
viewport_pos.y = -(ymargin * height - pl->position.y); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void accel_update_viewport(Body *pl) { |
||||||
|
const double accel = 0.0001; |
||||||
|
const float xmargin = 0.5; |
||||||
|
const float ymargin = 0.2; |
||||||
|
|
||||||
|
static Vect target_pos = (Vect) {.x=0, .y=0}; |
||||||
|
static Vect vel = (Vect) {.x=0.0, .y=0.0}; |
||||||
|
|
||||||
|
|
||||||
|
if (pl->position.x - viewport_pos.x > (1-xmargin) * width) { |
||||||
|
target_pos.x = - ((1-xmargin) * width - pl->position.x); |
||||||
|
}
|
||||||
|
|
||||||
|
if (pl->position.x - target_pos.x < xmargin * width) { |
||||||
|
target_pos.x = -(xmargin * width - pl->position.x); |
||||||
|
} |
||||||
|
|
||||||
|
if (pl->position.y - target_pos.y > (1-ymargin) * height) { |
||||||
|
target_pos.y = -((1-ymargin) * height - pl->position.y); |
||||||
|
}
|
||||||
|
|
||||||
|
if (pl->position.y - target_pos.y < ymargin * height) { |
||||||
|
target_pos.y = -(ymargin * height - pl->position.y); |
||||||
|
} |
||||||
|
|
||||||
|
viewport_pos = target_pos; |
||||||
|
return; |
||||||
|
|
||||||
|
Vect delta = vect_add(target_pos, vect_scalar(viewport_pos, -1)); |
||||||
|
printf("d %f %f\n", delta.x, delta.y); |
||||||
|
printf("d %f\n", vect_mag(delta)); |
||||||
|
|
||||||
|
if ((vect_mag(delta) < 0.001 )) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
Vect dir = vect_scalar(delta, 1/vect_mag(delta)); |
||||||
|
Vect vel_delta = vect_scalar(dir, accel * time_delta); |
||||||
|
vel = vect_add(vel, vel_delta); |
||||||
|
|
||||||
|
Vect pos_delta = vect_scalar(vel, time_delta/2); |
||||||
|
|
||||||
|
viewport_pos = vect_add(viewport_pos, pos_delta); |
||||||
|
} |
||||||
|
|
||||||
|
double interpolate_h(Vect left, Vect right, double x) { |
||||||
|
static Vect v; |
||||||
|
|
||||||
|
double m = (double)(right.y - left.y) / (double)(right.x - left.x);
|
||||||
|
double c = (double)left.y - ((double)left.x * m);
|
||||||
|
|
||||||
|
return x * m + c; |
||||||
|
} |
||||||
|
|
||||||
|
void draw_environment(SDL_Renderer * ren, const struct environment *scene) { |
||||||
|
struct colour c1 = scene->colours.bg; |
||||||
|
struct colour c2 = scene->colours.fg1; |
||||||
|
struct colour c3 = scene->colours.fg2; |
||||||
|
struct colour c4 = scene->colours.fg3; |
||||||
|
|
||||||
|
/*c1->r = 255;*/ |
||||||
|
/*c2->g = 255;*/ |
||||||
|
/*c3->b = 255;*/ |
||||||
|
/*c4->g = 255;*/ |
||||||
|
/*c4->b = 255;*/ |
||||||
|
|
||||||
|
// background colour
|
||||||
|
SDL_SetRenderDrawColor(ren, c1.r, c1.g, c1.b, 255); |
||||||
|
/*SDL_SetRenderDrawColor(ren, 255, 0, 0, 255);*/ |
||||||
|
|
||||||
|
SDL_Rect rect;
|
||||||
|
rect.x = 0; |
||||||
|
rect.y = 0; |
||||||
|
rect.w = width; |
||||||
|
rect.h = height; |
||||||
|
SDL_RenderFillRect(ren, &rect); |
||||||
|
|
||||||
|
/*
|
||||||
|
* double m = (double)(right.y - left.y) / (double)(right.x - left.x); |
||||||
|
* double c = (double)left.y - ((double)left.x * m); |
||||||
|
* |
||||||
|
* for (int i = left.x; i <= right.x; i++) { |
||||||
|
* int y = (int)(m * i + c); |
||||||
|
* if (y > 0) { |
||||||
|
* SDL_RenderDrawLine(ren, i, y, i, end); |
||||||
|
* } |
||||||
|
* } |
||||||
|
*/ |
||||||
|
|
||||||
|
int k = 0; |
||||||
|
// printf("from 0 to (room tiles) %d - 1, res %d width %d\n", E_ROOM_TILES, E_ROOM_RES, E_ROOM_WIDTH);
|
||||||
|
for (int i = 0; i < E_ROOM_TILES - 1; i++) { |
||||||
|
for (int j = 0; j < E_ROOM_RES; j++) { |
||||||
|
k++; |
||||||
|
Vect *left; |
||||||
|
Vect *right; |
||||||
|
|
||||||
|
int x = (i * E_ROOM_RES) + j; |
||||||
|
if (x - viewport_pos.x > width) { |
||||||
|
break; |
||||||
|
} |
||||||
|
if (x - viewport_pos.x < 0) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
left = arlst_get(&scene->ceil, i); |
||||||
|
right = arlst_get(&scene->ceil, i+1); |
||||||
|
|
||||||
|
int y0 = interpolate_h(*left, *right, x) - viewport_pos.y; |
||||||
|
|
||||||
|
left = arlst_get(&scene->bg1, i); |
||||||
|
right = arlst_get(&scene->bg1, i+1); |
||||||
|
|
||||||
|
int y1 = interpolate_h(*left, *right, x) - viewport_pos.y; |
||||||
|
|
||||||
|
left = arlst_get(&scene->bg2, i); |
||||||
|
right = arlst_get(&scene->bg2, i+1); |
||||||
|
|
||||||
|
int y2 = interpolate_h(*left, *right, x) - viewport_pos.y; |
||||||
|
|
||||||
|
left = arlst_get(&scene->floor, i); |
||||||
|
right = arlst_get(&scene->floor, i+1); |
||||||
|
|
||||||
|
int y3 = interpolate_h(*left, *right, x) - viewport_pos.y; |
||||||
|
|
||||||
|
x = x - viewport_pos.x; |
||||||
|
/*printf("x: %d, ", x);*/ |
||||||
|
/*printf("y: %d %d %d %d\n", y0, y1, y2, y3);*/ |
||||||
|
|
||||||
|
// 3. bg2 to floor
|
||||||
|
SDL_SetRenderDrawColor(ren, c4.r, c4.g, c4.b, 255); |
||||||
|
SDL_RenderDrawLine(ren, x, y2, x, y3); |
||||||
|
|
||||||
|
// 1. ceil to bg1
|
||||||
|
SDL_SetRenderDrawColor(ren, c2.r, c2.g, c2.b, 255); |
||||||
|
SDL_RenderDrawLine(ren, x, y0, x, y1); |
||||||
|
|
||||||
|
// 2. bg1 to bg2
|
||||||
|
SDL_SetRenderDrawColor(ren, c3.r, c3.g, c3.b, 255); |
||||||
|
SDL_RenderDrawLine(ren, x, y1, x, y2); |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void draw_text(SDL_Renderer *rend, Vect pos, struct colour colour, char *text) { |
||||||
|
static SDL_Renderer *ren = NULL; |
||||||
|
static TTF_Font* font = NULL; |
||||||
|
if (!font) { |
||||||
|
font = TTF_OpenFont("res/TerminusTTF.ttf", 44); |
||||||
|
const char *err = SDL_GetError(); |
||||||
|
if (err) { |
||||||
|
printf("%s\n", err); |
||||||
|
} |
||||||
|
} |
||||||
|
if (!ren) { |
||||||
|
ren = rend; |
||||||
|
} |
||||||
|
|
||||||
|
SDL_Colour sdl_col = {colour.r, colour.g, colour.b, 255};
|
||||||
|
SDL_Rect position = {.x = pos.x, .y = pos.y}; |
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(ren, colour.r, colour.g, colour.b, 255); |
||||||
|
SDL_Surface *surf = TTF_RenderText_Solid(font, text, sdl_col); |
||||||
|
|
||||||
|
SDL_Texture *texture = SDL_CreateTextureFromSurface(ren, surf); |
||||||
|
SDL_QueryTexture(texture, NULL, NULL, &position.w, &position.h); |
||||||
|
SDL_RenderCopy(ren, texture, NULL, &position); |
||||||
|
|
||||||
|
SDL_DestroyTexture(texture); |
||||||
|
SDL_FreeSurface(surf); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void draw_level_chooser_tbox(SDL_Renderer *ren) { |
||||||
|
|
||||||
|
char string[250]; |
||||||
|
snprintf(string, 250,"GOTO LEVEL: %s", gameui.currently_bound_textbox->text_input); |
||||||
|
|
||||||
|
const struct environment *scene = get_scene_watch(); |
||||||
|
|
||||||
|
Vect pos = {.x= width - (width / 4), .y = height - (height / 10)}; |
||||||
|
draw_text(ren, pos, scene->colours.fg1, string); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
int draw_end_screen(SDL_Renderer *ren) { |
||||||
|
const struct environment *scene = get_scene_watch(); |
||||||
|
|
||||||
|
struct colour bg = scene->colours.bg; |
||||||
|
struct colour colour = scene->colours.fg1; |
||||||
|
struct colour_pallete pal = scene->colours; |
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(ren, bg.r, bg.g, bg.b,255); |
||||||
|
|
||||||
|
SDL_RenderClear(ren); |
||||||
|
|
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(ren, pal.fg2.r, pal.fg2.g, pal.fg2.b,255); |
||||||
|
for (int i = width - 300; i < width; i++) { |
||||||
|
SDL_RenderDrawLine(ren, i, height, width, height - i); |
||||||
|
if (!(i % 240)) { |
||||||
|
SDL_SetRenderDrawColor(ren, pal.fg3.r, pal.fg3.g, pal.fg3.b,255); |
||||||
|
} |
||||||
|
if (!(i % 350)) { |
||||||
|
SDL_SetRenderDrawColor(ren, pal.fg1.r, pal.fg1.g, pal.fg1.b,255); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
int margin = height / 10; |
||||||
|
// Vect position = {.x = width - width / 10, .y = height - margin};
|
||||||
|
|
||||||
|
long fastest = draw_watch.best_time; |
||||||
|
|
||||||
|
int minutes = level_time / 60000; |
||||||
|
float seconds = level_time * 0.001; |
||||||
|
char time_string[250]; |
||||||
|
|
||||||
|
|
||||||
|
char * end_str = "level over."; |
||||||
|
|
||||||
|
Vect position = {.x = width/4, .y = height / 4}; |
||||||
|
draw_text(ren, position, colour, end_str); |
||||||
|
position.y += 60; |
||||||
|
|
||||||
|
char level_string[250]; |
||||||
|
snprintf(level_string, 250,"course: %d", level); |
||||||
|
draw_text(ren, position, colour, level_string); |
||||||
|
position.y += 40; |
||||||
|
|
||||||
|
char fastest_time[250]; |
||||||
|
minutes = fastest / 60000; |
||||||
|
seconds = fastest * 0.001; |
||||||
|
if (fastest > 0) { |
||||||
|
snprintf(fastest_time, 250, "old best time: %d:%.4f", minutes, seconds); |
||||||
|
draw_text(ren, position, colour, fastest_time); |
||||||
|
position.y += 40; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
char qual_str[250]; |
||||||
|
snprintf(qual_str, 250, "physics quality: %d", quality); |
||||||
|
draw_text(ren, position, colour, qual_str); |
||||||
|
position.y += 40; |
||||||
|
*/ |
||||||
|
|
||||||
|
|
||||||
|
minutes = level_time / 60000; |
||||||
|
seconds = level_time * 0.001; |
||||||
|
if (level_time > fastest) { |
||||||
|
// base time not set yet.
|
||||||
|
snprintf(time_string, 250, "TIME: %d:%.4f", minutes, seconds); |
||||||
|
} else { |
||||||
|
snprintf(time_string, 250, "NEW BEST TIME: %d:%.4f", minutes, seconds); |
||||||
|
} |
||||||
|
|
||||||
|
Vect position2 = {.x = position.x + width/3, .y = 60 + height / 4}; |
||||||
|
|
||||||
|
if (fastest > 0) { |
||||||
|
//position.y += 40;
|
||||||
|
long diff = level_time - fastest; |
||||||
|
char diff_str[250]; |
||||||
|
minutes = diff / 60000; |
||||||
|
seconds = diff * 0.001; |
||||||
|
if (minutes > 0) { |
||||||
|
snprintf(diff_str, 250, "DIFF: %d:%.4f", minutes, fabs(seconds)); |
||||||
|
} else { |
||||||
|
snprintf(diff_str, 250, "DIFF: %.4f s", seconds); |
||||||
|
} |
||||||
|
|
||||||
|
draw_text(ren, position2, colour, diff_str); |
||||||
|
position2.y += 40; |
||||||
|
} |
||||||
|
|
||||||
|
draw_text(ren, position2, colour, time_string); |
||||||
|
|
||||||
|
position.y += 200; |
||||||
|
char * ct_str = "press any key to continue"; |
||||||
|
draw_text(ren, position, colour, ct_str); |
||||||
|
|
||||||
|
SDL_RenderPresent(ren); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void draw_level_time(SDL_Renderer *ren, const struct environment * e) { |
||||||
|
|
||||||
|
int margin = height / 10; |
||||||
|
|
||||||
|
struct colour colour = e->colours.fg1; |
||||||
|
|
||||||
|
int minutes = level_time / 60000; |
||||||
|
float seconds = level_time * 0.001; |
||||||
|
char time_string[250]; |
||||||
|
snprintf(time_string, 250, "time: %d:%.4f", minutes, seconds); |
||||||
|
|
||||||
|
char level_string[250]; |
||||||
|
snprintf(level_string, 250,"course: %d", level); |
||||||
|
|
||||||
|
Vect position = {.x = margin, .y = height - margin}; |
||||||
|
draw_text(ren, position, colour, level_string); |
||||||
|
position.y += 40; |
||||||
|
draw_text(ren, position, colour, time_string); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void draw_pause_screen(SDL_Renderer *ren, struct environment *e) { |
||||||
|
|
||||||
|
char *te[] = { "GAME PAUSED.", |
||||||
|
"controls", |
||||||
|
"________", |
||||||
|
"pause/unpause: esc", |
||||||
|
"grapple: right click", |
||||||
|
"grapple and pull: left click", |
||||||
|
"go to level: g", |
||||||
|
"mute/unmute: m", |
||||||
|
"quit: q" |
||||||
|
}; |
||||||
|
|
||||||
|
struct colour textc = e->colours.fg1; |
||||||
|
struct colour bg = e->colours.bg; |
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(ren, bg.r, bg.g, bg.b, 255); |
||||||
|
int boxwidth = 360; |
||||||
|
int boxheight = 348; |
||||||
|
int box_x = (2 * width / 3) - (boxwidth / 2); |
||||||
|
int box_y = (height - boxheight) / 2; |
||||||
|
SDL_Rect r = {.w = boxwidth, .h = boxheight, .x = box_x, .y = box_y}; |
||||||
|
SDL_RenderFillRect(ren, &r); |
||||||
|
|
||||||
|
Vect p = {.x = box_x + 10, .y = box_y + 10}; |
||||||
|
draw_text(ren, p, textc, te[0]); |
||||||
|
p.y += 60; |
||||||
|
|
||||||
|
draw_text(ren, p, textc, te[1]); |
||||||
|
p.y += 5; |
||||||
|
draw_text(ren, p, textc, te[2]); |
||||||
|
p.y += 35; |
||||||
|
|
||||||
|
draw_text(ren, p, textc, te[3]); |
||||||
|
p.y += 40; |
||||||
|
|
||||||
|
draw_text(ren, p, textc, te[4]); |
||||||
|
p.y += 40; |
||||||
|
|
||||||
|
draw_text(ren, p, textc, te[5]); |
||||||
|
p.y += 40; |
||||||
|
|
||||||
|
draw_text(ren, p, textc, te[6]); |
||||||
|
p.y += 40; |
||||||
|
|
||||||
|
draw_text(ren, p, textc, te[7]); |
||||||
|
p.y += 40; |
||||||
|
|
||||||
|
draw_text(ren, p, textc, te[8]); |
||||||
|
p.y += 40; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void redraw_buffer(SDL_Renderer * ren) { |
||||||
|
static int mousex = 0; |
||||||
|
static int mousey = 0; |
||||||
|
static int newmousex = 0;
|
||||||
|
static int newmousey = 0; |
||||||
|
static SDL_Point *bgPixels[256]; |
||||||
|
static int numpixels[256]; |
||||||
|
|
||||||
|
/*if (!width && !height) {*/ |
||||||
|
/*for (int i = 0; i < 256; i++) {*/ |
||||||
|
/*bgPixels[i] = malloc(sizeof(SDL_Point) * width * height);*/ |
||||||
|
/*memset(bgPixels[i], 0, sizeof(SDL_Point) * width * height);*/ |
||||||
|
/*memset(numpixels, 0, (sizeof(int) * 256));*/ |
||||||
|
/*}*/ |
||||||
|
/*}*/ |
||||||
|
|
||||||
|
int col = 0; |
||||||
|
Body lplayer; |
||||||
|
|
||||||
|
if (SDL_LockMutex(player.physics->lock) == 0){ |
||||||
|
lplayer = *player.physics; |
||||||
|
update_viewport(&lplayer); |
||||||
|
} else { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
static struct timespec last = {}; |
||||||
|
static struct timespec now; |
||||||
|
now = get_now_d(); |
||||||
|
time_delta = now.tv_nsec - last.tv_nsec; |
||||||
|
time_delta *= 0.000001; // convert to ms from ns
|
||||||
|
|
||||||
|
last = now; |
||||||
|
|
||||||
|
//SDL_GetMouseState(&newmousex, &newmousey);
|
||||||
|
|
||||||
|
const struct environment* scene = get_scene_watch(); |
||||||
|
draw_environment(ren, scene); |
||||||
|
draw_level_time(ren, scene); |
||||||
|
SDL_UnlockMutex(player.physics->lock); |
||||||
|
|
||||||
|
for (int i=0; i < world.items.size; i++) { |
||||||
|
world_thing thing; |
||||||
|
thing = world.get(i); |
||||||
|
|
||||||
|
switch (thing.kind) { |
||||||
|
case STATIC_WALL_W: |
||||||
|
draw_wall(ren, thing.wall); |
||||||
|
draw_collision_poly(ren, thing.wall->physics); |
||||||
|
continue; |
||||||
|
case FLOOR: |
||||||
|
for (int i = 0; i < thing.floor->numPolys; i++) { |
||||||
|
draw_floor(ren, &thing.floor->polys[i], true); |
||||||
|
draw_collision_poly(ren, thing.floor->polys[i].physics); |
||||||
|
} |
||||||
|
continue; |
||||||
|
case CEILING: |
||||||
|
for (int i = 0; i < thing.floor->numPolys; i++) { |
||||||
|
draw_floor(ren, &thing.floor->polys[i], false); |
||||||
|
draw_collision_poly(ren, thing.floor->polys[i].physics); |
||||||
|
} |
||||||
|
continue; |
||||||
|
case ROOM_W: |
||||||
|
for (int i = 0; i < thing.room->ceil.numItems; i++) { |
||||||
|
draw_collision_poly(ren, thing.room->ceil.items[i]); |
||||||
|
} |
||||||
|
for (int i = 0; i < thing.room->floor.numItems; i++) { |
||||||
|
draw_collision_poly(ren, thing.room->floor.items[i]); |
||||||
|
} |
||||||
|
default: |
||||||
|
continue; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
draw_player(ren, lplayer.position.x, lplayer.position.y,
|
||||||
|
lplayer.colliding); |
||||||
|
draw_collision_poly(ren, &lplayer); |
||||||
|
draw_forces(ren, &lplayer); |
||||||
|
|
||||||
|
if (gameui.currently_bound_textbox) { |
||||||
|
draw_level_chooser_tbox(ren); |
||||||
|
} |
||||||
|
|
||||||
|
if (game_paused) { |
||||||
|
SDL_Rect r = {.x = 0, .y = 0, .w = width, .h = height}; |
||||||
|
SDL_SetRenderDrawColor(ren, 0, 0, 0, 90); |
||||||
|
SDL_RenderFillRect(ren, &r); |
||||||
|
if (in_game) |
||||||
|
draw_pause_screen(ren, scene); |
||||||
|
} |
||||||
|
|
||||||
|
/*if (newmousex != mousex || newmousey != mousey) {*/ /*mousey = newmousey;*/ |
||||||
|
/*mousex = newmousex;*/ |
||||||
|
/*for (int i = 0; i < 256; i++) {*/ |
||||||
|
/*memset(bgPixels[i], 0, sizeof(SDL_Point) * width * height);*/ |
||||||
|
/*memset(numpixels, 0, (sizeof(int) * 256));*/ |
||||||
|
/*}*/ |
||||||
|
/*for (int i=0; i < width; i++) {*/ |
||||||
|
/*for (int j = 0; j < height; j++) {*/ |
||||||
|
/*col = distance_colour(i, j, mousex, mousey, 10000);*/ |
||||||
|
|
||||||
|
/*SDL_Point *row = bgPixels[col];*/ |
||||||
|
/*SDL_Point point;*/ |
||||||
|
/*point.x = i;*/ |
||||||
|
/*point.y = j;*/ |
||||||
|
/*row[numpixels[col]] = point;*/ |
||||||
|
/*numpixels[col] += 1;*/ |
||||||
|
|
||||||
|
/*}*/ |
||||||
|
/*}*/ |
||||||
|
/*}*/ |
||||||
|
|
||||||
|
/*for (int i = 0; i < 255; i++) {*/ |
||||||
|
/*SDL_Point *row = bgPixels[i];*/ |
||||||
|
/*col = i;*/ |
||||||
|
/*SDL_SetRenderDrawColor(ren, col, col, col, 255);*/ |
||||||
|
/*SDL_RenderDrawPoints(ren, row, numpixels[i]);*/ |
||||||
|
/*}*/ |
||||||
|
|
||||||
|
} |
||||||
|
|
@ -0,0 +1,42 @@ |
|||||||
|
#ifndef _DEFDRAW |
||||||
|
#define _DEFDRAW |
||||||
|
|
||||||
|
#include <SDL.h> |
||||||
|
#include <SDL_ttf.h> |
||||||
|
|
||||||
|
#include "colours.h" |
||||||
|
#include "vect.h" |
||||||
|
#include "environment.h" |
||||||
|
#include "game.h" |
||||||
|
|
||||||
|
#define SHOWCOLLISION 0 |
||||||
|
#define SHOWFORCES 0 |
||||||
|
|
||||||
|
typedef enum { |
||||||
|
PLAYER |
||||||
|
} draw_type; |
||||||
|
|
||||||
|
void render_texture_at(struct SDL_Renderer * ren, struct SDL_Texture * texture,int x, int y) ; |
||||||
|
/* draw a texture at x.y */ |
||||||
|
|
||||||
|
SDL_Texture * load_image(SDL_Renderer * ren, char fname[]);
|
||||||
|
/* Load an image into a texture */ |
||||||
|
|
||||||
|
void draw_player(SDL_Renderer * ren, int x, int y, bool red);
|
||||||
|
/* draw the player as a coloured rect */ |
||||||
|
|
||||||
|
//void queue_draw_item(void * object, draw_type kind);
|
||||||
|
void add_to_view(draw_type kind, void * object);
|
||||||
|
|
||||||
|
void redraw_buffer(SDL_Renderer * ren);
|
||||||
|
|
||||||
|
void draw_text(SDL_Renderer *ren, Vect pos, struct colour colour, char *text);
|
||||||
|
|
||||||
|
int draw_end_screen(SDL_Renderer *ren);
|
||||||
|
|
||||||
|
extern Vect viewport_pos; |
||||||
|
extern int width, height; |
||||||
|
extern bool high_contrast_mode; |
||||||
|
|
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,244 @@ |
|||||||
|
#include "environment.h" |
||||||
|
#include "game.h" |
||||||
|
#include "types.h" |
||||||
|
|
||||||
|
struct environment * environment_watch = NULL; |
||||||
|
|
||||||
|
const struct environment* get_scene_watch(void) { |
||||||
|
return environment_watch; |
||||||
|
} |
||||||
|
|
||||||
|
double linear_interpolate(double a0, double a1, double w) { |
||||||
|
return (1.0f - w) * a0 + w * a1; |
||||||
|
} |
||||||
|
|
||||||
|
int destroy_environment(struct environment *e) { |
||||||
|
/*Vect position;*/ |
||||||
|
/*ArrayList ceil; // doubles*/ |
||||||
|
/*ArrayList floor; // doubles*/ |
||||||
|
/*ArrayList bg1; // doubles*/ |
||||||
|
/*ArrayList bg2; // doubles*/ |
||||||
|
/*struct colour_pallete colours;*/ |
||||||
|
/*struct physics_collection physics;*/ |
||||||
|
|
||||||
|
arlst_destroy(&e->ceil); |
||||||
|
arlst_destroy(&e->floor); |
||||||
|
arlst_destroy(&e->bg1); |
||||||
|
arlst_destroy(&e->bg2); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
double perlin(Vect coordinate) { |
||||||
|
Vect a = coordinate; |
||||||
|
Vect b = coordinate; |
||||||
|
a.x = (int)a.x; |
||||||
|
a.y = (int)a.y; |
||||||
|
b.x = a.x + 1; |
||||||
|
b.y = a.y + 1; |
||||||
|
|
||||||
|
double sx = coordinate.x - a.x; |
||||||
|
double sy = coordinate.y - a.y; |
||||||
|
|
||||||
|
Vect d = b; |
||||||
|
d.y = a.y; |
||||||
|
|
||||||
|
double n0 = vect_dot(a, coordinate); |
||||||
|
double n1 = vect_dot(d, coordinate); |
||||||
|
|
||||||
|
double ix0 = linear_interpolate(n0, n1, sx); |
||||||
|
|
||||||
|
Vect c; |
||||||
|
c.x = a.x; |
||||||
|
c.y = b.y; |
||||||
|
|
||||||
|
n0 = vect_dot(c, coordinate); |
||||||
|
n1 = vect_dot(b, coordinate); |
||||||
|
double ix1 = linear_interpolate(n0, n1, sy); |
||||||
|
|
||||||
|
return linear_interpolate(ix0, ix1, sy); |
||||||
|
} |
||||||
|
|
||||||
|
struct colour_pallete get_pallete_high_contrast(void) { |
||||||
|
struct colour white = {.r = 255, .g=255,.b=255, .sp=CS_RGB}; |
||||||
|
struct colour black = {.r = 0, .g=0,.b=0, .sp=CS_RGB}; |
||||||
|
struct colour_pallete p = {.bg = black, .fg1 = white, .fg2 = white, .fg3 = white}; |
||||||
|
return p; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
struct colour_pallete get_pallete (int seed) { |
||||||
|
struct colour base; |
||||||
|
|
||||||
|
if (high_contrast_mode)
|
||||||
|
return get_pallete_high_contrast(); |
||||||
|
|
||||||
|
int n = seed; |
||||||
|
int red = get_rand(&n) % 255; |
||||||
|
int blue = get_rand(&n) % 255; |
||||||
|
int green = get_rand(&n) % 255; |
||||||
|
|
||||||
|
base.r = red; |
||||||
|
base.g = green; |
||||||
|
base.b = blue; |
||||||
|
|
||||||
|
struct colour c1 = get_hsv(base); |
||||||
|
c1 = get_hsv(base); |
||||||
|
struct colour_pallete cols; |
||||||
|
|
||||||
|
c1.l = 0.1; |
||||||
|
cols.bg = get_rgb(c1); |
||||||
|
c1.l += 0.3; |
||||||
|
|
||||||
|
c1.h += 30; |
||||||
|
cols.fg1 = get_rgb(c1); |
||||||
|
|
||||||
|
c1.h += 30; |
||||||
|
cols.fg2 = get_rgb(c1); |
||||||
|
|
||||||
|
c1.h += 30; |
||||||
|
cols.fg3 = get_rgb(c1); |
||||||
|
|
||||||
|
return cols; |
||||||
|
|
||||||
|
struct colour *adj = get_adjacent(base, 20, 4); |
||||||
|
ArrayList l = new_arlst_wfree(4, free); |
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) { |
||||||
|
arlst_add(&l, adj + i); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
int comp(const void *one, const void *two) { |
||||||
|
return *(int*)one >= *(int*)two; |
||||||
|
} |
||||||
|
|
||||||
|
struct environment get_scene_at(Vect coordinate, int seed) { |
||||||
|
// TODO: Environment needs to be shared between threads
|
||||||
|
// - this implementation duplicates it: each thread that calls
|
||||||
|
// get_scene_at gets manages its state in its own static vairables in
|
||||||
|
// this function but share pointers to the malloced environment object-
|
||||||
|
// it is thoroughly broken.
|
||||||
|
// - Fix by having a heap allocated environment object that the draw thread
|
||||||
|
// (T0) can watch and the physics thread (T3) can modify
|
||||||
|
// - the entry point can either be through a function returning
|
||||||
|
// a pointer or just a global const pointer
|
||||||
|
//
|
||||||
|
// basic cache for the last room generated
|
||||||
|
static bool init; |
||||||
|
static Vect last_room; |
||||||
|
static struct environment e; |
||||||
|
static int oldseed; |
||||||
|
Vect room_coord; |
||||||
|
room_coord.x = (int)coordinate.x - (int)coordinate.x % E_ROOM_WIDTH; |
||||||
|
room_coord.y = 0; |
||||||
|
|
||||||
|
if (init && room_coord.x == last_room.x && oldseed == seed) { |
||||||
|
return e; |
||||||
|
} else if (init) { |
||||||
|
destroy_environment(&e); |
||||||
|
} |
||||||
|
last_room = room_coord; |
||||||
|
oldseed = seed; |
||||||
|
|
||||||
|
e.floor = new_arlst_wfree(E_ROOM_TILES, free); |
||||||
|
e.ceil = new_arlst_wfree(E_ROOM_TILES, free); |
||||||
|
e.bg1 = new_arlst_wfree(E_ROOM_TILES, free); |
||||||
|
e.bg2 = new_arlst_wfree(E_ROOM_TILES, free); |
||||||
|
|
||||||
|
e.colours = get_pallete(seed); |
||||||
|
|
||||||
|
Vect bit; |
||||||
|
bit.y = 100 * seed; |
||||||
|
Vect pos; |
||||||
|
|
||||||
|
int n = seed; |
||||||
|
get_rand(&n); |
||||||
|
|
||||||
|
Vect node; |
||||||
|
node.y = 0; |
||||||
|
|
||||||
|
for (int i = 0; i < E_ROOM_WIDTH; i += E_ROOM_RES) { |
||||||
|
bit.x = room_coord.x + i; |
||||||
|
bit.y = seed; |
||||||
|
node.x = bit.x; |
||||||
|
|
||||||
|
int r1 = 1.5*(get_rand(&n) % 500) - (get_rand(&n) % 100);
|
||||||
|
int r2 = 1.5*(get_rand(&n) % 200) - (get_rand(&n) % 200); |
||||||
|
int r3 = (get_rand(&n) % 100) - (get_rand(&n) % 500); |
||||||
|
int r4 = 50; |
||||||
|
|
||||||
|
int r[4] = {r1, r2, r3, r4}; |
||||||
|
qsort(r, 4, sizeof(int), comp); |
||||||
|
// r[0] == ceiling
|
||||||
|
// r[3] == floor
|
||||||
|
|
||||||
|
//node.y += r[0];
|
||||||
|
int h[4] = {node.y,node.y,node.y,node.y}; |
||||||
|
h[0] += r[0]; |
||||||
|
h[1] = h[0] + r[1]; |
||||||
|
h[2] += h[0] + r[2]; |
||||||
|
h[3] += h[0] + r[3]; |
||||||
|
qsort(h, 4, sizeof(int), comp); |
||||||
|
|
||||||
|
// node.y = fmod(perlin(bit), 3000);
|
||||||
|
Vect *z = malloc(sizeof(Vect)); |
||||||
|
*z = node; |
||||||
|
z->y = h[0]; |
||||||
|
|
||||||
|
arlst_add(&e.floor, z); |
||||||
|
|
||||||
|
z = malloc(sizeof(Vect)); |
||||||
|
*z = node; |
||||||
|
// z->y += r[1];
|
||||||
|
z->y = h[1]; |
||||||
|
arlst_add(&e.bg1, z); |
||||||
|
|
||||||
|
z = malloc(sizeof(Vect)); |
||||||
|
*z = node; |
||||||
|
//z->y += r[2];
|
||||||
|
z->y = h[2]; |
||||||
|
arlst_add(&e.bg2, z); |
||||||
|
|
||||||
|
|
||||||
|
z = malloc(sizeof(Vect)); |
||||||
|
*z = node; |
||||||
|
// z->y += r[3];
|
||||||
|
z->y = h[3]; |
||||||
|
arlst_add(&e.ceil, z); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Vect *v = arlst_get(&e.floor, 0);
|
||||||
|
Vect v2 = *(Vect *)arlst_get(&e.ceil, 0);
|
||||||
|
|
||||||
|
Vect v3 = vect_add(v2, vect_scalar(vect_add(*v, vect_scalar(v2, -1)) , 0.5)); |
||||||
|
|
||||||
|
int d[] = {0, E_ROOM_TILES - 1}; |
||||||
|
int a; |
||||||
|
for (int i = 0; i <= 1; i++) { |
||||||
|
a = d[i]; |
||||||
|
v = arlst_get(&e.floor, a);
|
||||||
|
v->y = v3.x; |
||||||
|
v = arlst_get(&e.ceil, a);
|
||||||
|
v->y = v3.x; |
||||||
|
v = arlst_get(&e.bg1, a);
|
||||||
|
v->y = v3.x; |
||||||
|
v = arlst_get(&e.bg2, a);
|
||||||
|
v->y = v3.x; |
||||||
|
} |
||||||
|
|
||||||
|
// join the end and start together
|
||||||
|
|
||||||
|
if (!init) { |
||||||
|
struct environment *ee = malloc(sizeof(struct environment)); |
||||||
|
environment_watch = ee; |
||||||
|
} |
||||||
|
|
||||||
|
*environment_watch = e; |
||||||
|
|
||||||
|
init = true; |
||||||
|
|
||||||
|
return e; |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
#ifndef ENVIRO_H |
||||||
|
#define ENVIRO_H |
||||||
|
|
||||||
|
#include "vect.h" |
||||||
|
#include "types.h" |
||||||
|
|
||||||
|
struct environment get_scene_at(Vect coordinate, int seed);
|
||||||
|
int destroy_environment(struct environment *e); |
||||||
|
|
||||||
|
const struct environment *get_scene_watch(void); |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,82 @@ |
|||||||
|
#ifndef _DEFGAME |
||||||
|
#define _DEFGAME |
||||||
|
|
||||||
|
#include "environment.h" |
||||||
|
#include "datatypes.h" |
||||||
|
#include "vect.h" |
||||||
|
#include "controlscheme.h" |
||||||
|
#include "colours.h" |
||||||
|
#include "types.h" |
||||||
|
#include "draw.h" |
||||||
|
|
||||||
|
extern GlobWorld world; |
||||||
|
extern int level; |
||||||
|
extern bool in_game; |
||||||
|
extern int quality; |
||||||
|
|
||||||
|
struct draw_watcher { |
||||||
|
long best_time; |
||||||
|
bool finish_level; |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
struct ui_state { |
||||||
|
struct textbox_info *currently_bound_textbox; |
||||||
|
int goto_new_level; |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
enum TextBoxId { |
||||||
|
TB_LEVEL_CHOOSER = 0 |
||||||
|
}; |
||||||
|
|
||||||
|
struct textbox_info { |
||||||
|
enum TextBoxId id; |
||||||
|
bool capture_input_text_field; |
||||||
|
char text_input[32]; |
||||||
|
int text_input_bufpos; |
||||||
|
void (*close_callback)(struct textbox_info *textbox, void*callback); |
||||||
|
}; |
||||||
|
|
||||||
|
extern struct draw_watcher draw_watch; |
||||||
|
extern struct textbox_info* texboxes; |
||||||
|
extern struct ui_state gameui; |
||||||
|
|
||||||
|
|
||||||
|
void handle_input_event(SDL_Event event); |
||||||
|
|
||||||
|
// add a motor to the world
|
||||||
|
void add_motor(Body *thing, double x, double y);
|
||||||
|
|
||||||
|
bool get_motor_active(Body *thing, int i);
|
||||||
|
|
||||||
|
/* temporary storage variable *n should be initialised to the seed value */ |
||||||
|
int get_rand(int *n);
|
||||||
|
|
||||||
|
void next_level(int lvl);
|
||||||
|
|
||||||
|
int step(void); |
||||||
|
|
||||||
|
struct sg_times_list { |
||||||
|
long *times; |
||||||
|
int size; |
||||||
|
int capacity; |
||||||
|
void (*sort)(void); |
||||||
|
char *filename; |
||||||
|
}; |
||||||
|
|
||||||
|
int load_score_times(char *filename);
|
||||||
|
|
||||||
|
|
||||||
|
/* array of all the things in the world and their kinds */ |
||||||
|
|
||||||
|
extern struct sg_times_list save_times_lst; |
||||||
|
int add_time(long time);
|
||||||
|
int write_times(void);
|
||||||
|
extern void startgame(SDL_Renderer * ren) ; |
||||||
|
extern void process_keydown(SDL_Keysym key); |
||||||
|
extern void process_keyup(SDL_Keysym key); |
||||||
|
extern player_st player; |
||||||
|
extern long level_time; |
||||||
|
extern bool game_paused; |
||||||
|
#endif |
@ -0,0 +1,185 @@ |
|||||||
|
#include <SDL_mutex.h> |
||||||
|
#include <SDL_audio.h> |
||||||
|
#include <SDL_scancode.h> |
||||||
|
#include <SDL_mixer.h> |
||||||
|
#include <stdio.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
#include <SDL.h> |
||||||
|
#include <string.h> |
||||||
|
#include <time.h> |
||||||
|
#include <stdbool.h> |
||||||
|
#include <math.h> |
||||||
|
|
||||||
|
#include "audio.h" // only for mkdirat lol |
||||||
|
#include <fcntl.h> |
||||||
|
#include <sys/stat.h> |
||||||
|
|
||||||
|
#include "game.h" |
||||||
|
#include "draw.h" |
||||||
|
#include "types.h" |
||||||
|
|
||||||
|
const int screen_width = 800; |
||||||
|
const int screen_height = 600; |
||||||
|
|
||||||
|
|
||||||
|
SDL_sem *resume; |
||||||
|
|
||||||
|
|
||||||
|
struct SDL_Window* make_window(void) { |
||||||
|
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
|
||||||
|
printf("error initializing SDL: %s\n", SDL_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return SDL_CreateWindow("space_game",
|
||||||
|
SDL_WINDOWPOS_CENTERED,
|
||||||
|
SDL_WINDOWPOS_CENTERED,
|
||||||
|
0, 0,
|
||||||
|
SDL_WINDOW_FULLSCREEN_DESKTOP);
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void redraw(struct SDL_Renderer * ren) { |
||||||
|
SDL_RenderClear(ren); |
||||||
|
redraw_buffer(ren); |
||||||
|
SDL_RenderPresent(ren); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void godophysics(void) { |
||||||
|
int lvl; |
||||||
|
if ((lvl = step())) { |
||||||
|
// display end level screen
|
||||||
|
in_game = false; |
||||||
|
game_paused = true; |
||||||
|
SDL_Delay(300); |
||||||
|
SDL_SemWait(resume); |
||||||
|
#ifdef SCORE_SYSTEM |
||||||
|
add_time(level_time); |
||||||
|
#endif |
||||||
|
|
||||||
|
SDL_LockMutex(player.physics->lock); |
||||||
|
next_level(lvl); |
||||||
|
in_game = true; |
||||||
|
SDL_UnlockMutex(player.physics->lock); |
||||||
|
game_paused = false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int physics_loop(void *ptr) { |
||||||
|
game_paused = 1; |
||||||
|
while (1) { |
||||||
|
godophysics(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int game(void) { |
||||||
|
//SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "2" );
|
||||||
|
|
||||||
|
SDL_Window * win = make_window(); |
||||||
|
SDL_Renderer * ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED); |
||||||
|
// | SDL_RENDERER_PRESENTVSYNC);
|
||||||
|
SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND); |
||||||
|
|
||||||
|
|
||||||
|
in_game = true; |
||||||
|
resume = SDL_CreateSemaphore(0); |
||||||
|
|
||||||
|
// IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG);
|
||||||
|
|
||||||
|
if (ren == NULL) { |
||||||
|
SDL_DestroyWindow(win); |
||||||
|
SDL_Quit(); |
||||||
|
} |
||||||
|
|
||||||
|
TTF_Init(); |
||||||
|
|
||||||
|
int close = 0; |
||||||
|
|
||||||
|
//draw_pictures(ren);
|
||||||
|
|
||||||
|
SDL_Thread *physics_thread; |
||||||
|
int ignore; |
||||||
|
|
||||||
|
startgame(ren); |
||||||
|
|
||||||
|
physics_thread = SDL_CreateThread(physics_loop, "physics", (void *)ren); |
||||||
|
|
||||||
|
int count = 0; |
||||||
|
|
||||||
|
while (!close) { |
||||||
|
SDL_Event event;
|
||||||
|
while(SDL_PollEvent(&event)) { |
||||||
|
switch (event.type) { |
||||||
|
case SDL_QUIT: |
||||||
|
goto endfunc; |
||||||
|
case SDL_KEYDOWN: |
||||||
|
if (event.key.keysym.scancode == SDL_SCANCODE_Q) { |
||||||
|
goto endfunc; |
||||||
|
} |
||||||
|
if (!in_game && !SDL_SemValue(resume)) { |
||||||
|
SDL_SemPost(resume); |
||||||
|
} |
||||||
|
case SDL_KEYUP: |
||||||
|
case SDL_MOUSEBUTTONDOWN: |
||||||
|
if (!in_game && !SDL_SemValue(resume)) { |
||||||
|
SDL_SemPost(resume); |
||||||
|
break; |
||||||
|
} |
||||||
|
case SDL_MOUSEBUTTONUP: |
||||||
|
handle_input_event (event); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!in_game && draw_watch.finish_level) { |
||||||
|
draw_end_screen(ren); |
||||||
|
} else { |
||||||
|
redraw(ren); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
endfunc: |
||||||
|
|
||||||
|
SDL_DestroyRenderer(ren); |
||||||
|
SDL_DestroyWindow(win); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
int main (int argc, char** argv) { |
||||||
|
|
||||||
|
#ifdef __linux__ |
||||||
|
mkdirat(AT_FDCWD, "saves", 0777); |
||||||
|
#elif WIN32 |
||||||
|
if (access("saves", 0) == 0) { |
||||||
|
struct stat status; |
||||||
|
stat("saves", &status ); |
||||||
|
if ((status.st_mode & S_IFDIR) == 0) { |
||||||
|
_mkdir("saves"); |
||||||
|
} |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
game(); |
||||||
|
|
||||||
|
SDL_Quit(); |
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO:
|
||||||
|
* - Allow setting and saving/loading differnet control schemes |
||||||
|
* - Allow starting a specific level |
||||||
|
* - Allow adjusging level lengths? |
||||||
|
* - Ensure next_level doesn't leak memory |
||||||
|
* - fix that weird jitter |
||||||
|
* - make the end of level look sane |
||||||
|
* - restart level |
||||||
|
* - make sure goto level doesn't log an end-0f-level time |
||||||
|
*/ |
||||||
|
|
@ -0,0 +1,61 @@ |
|||||||
|
#include <SDL.h> |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
int main(int /*argc*/, char* /*argv*/[]) { |
||||||
|
|
||||||
|
SDL_Window *window; // Declare a pointer
|
||||||
|
|
||||||
|
SDL_Init(SDL_INIT_VIDEO); // Initialize SDL2
|
||||||
|
|
||||||
|
// Create an application window with the following settings:
|
||||||
|
window = SDL_CreateWindow( |
||||||
|
"An SDL2 window", // window title
|
||||||
|
SDL_WINDOWPOS_UNDEFINED, // initial x position
|
||||||
|
SDL_WINDOWPOS_UNDEFINED, // initial y position
|
||||||
|
640, // width, in pixels
|
||||||
|
480, // height, in pixels
|
||||||
|
SDL_WINDOW_OPENGL // flags - see below
|
||||||
|
); |
||||||
|
|
||||||
|
// Check that the window was successfully created
|
||||||
|
if (window == NULL) { |
||||||
|
// In the case that the window could not be made...
|
||||||
|
printf("Could not create window: %s\n", SDL_GetError()); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
// The window is open: could enter program loop here (see SDL_PollEvent())
|
||||||
|
// Setup renderer
|
||||||
|
SDL_Renderer* renderer = NULL; |
||||||
|
renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED); |
||||||
|
|
||||||
|
// Set render color to red ( background will be rendered in this color )
|
||||||
|
SDL_SetRenderDrawColor( renderer, 255, 0, 0, 255 ); |
||||||
|
|
||||||
|
// Clear winow
|
||||||
|
SDL_RenderClear( renderer ); |
||||||
|
|
||||||
|
// bouyatest
|
||||||
|
|
||||||
|
// Creat a rect at pos ( 50, 50 ) that's 50 pixels wide and 50 pixels high.
|
||||||
|
SDL_Rect r; |
||||||
|
r.x = 50; |
||||||
|
r.y = 50; |
||||||
|
r.w = 500; |
||||||
|
r.h = 500; |
||||||
|
|
||||||
|
// Set render color to blue ( rect will be rendered in this color )
|
||||||
|
SDL_SetRenderDrawColor( renderer, 0, 200, 255, 255 ); |
||||||
|
|
||||||
|
// Render the rect to the screen
|
||||||
|
SDL_RenderPresent(renderer); |
||||||
|
|
||||||
|
SDL_Delay(1000); // Pause execution for 3000 milliseconds, for example
|
||||||
|
|
||||||
|
// Close and destroy the window
|
||||||
|
SDL_DestroyWindow(window); |
||||||
|
|
||||||
|
// Clean up
|
||||||
|
SDL_Quit(); |
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,2 @@ |
|||||||
|
#include "physics.h" |
||||||
|
#include "types.h" |
@ -0,0 +1,236 @@ |
|||||||
|
|
||||||
|
#ifndef PTYPES_H |
||||||
|
#define PTYPES_H |
||||||
|
|
||||||
|
#include <SDL_mutex.h> |
||||||
|
#include <SDL_audio.h> |
||||||
|
#include <SDL_scancode.h> |
||||||
|
#include <SDL_mixer.h> |
||||||
|
#include <stdio.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
#include <SDL.h> |
||||||
|
#include <string.h> |
||||||
|
#include <time.h> |
||||||
|
#include <stdbool.h> |
||||||
|
#include <math.h> |
||||||
|
|
||||||
|
#include "colours.h" |
||||||
|
#include "datatypes.h" |
||||||
|
#include "vect.h" |
||||||
|
|
||||||
|
enum motors { |
||||||
|
M_GRAVITY = 0, |
||||||
|
M_FRICTION = 1, |
||||||
|
M_PLAYER_WALK = 2, |
||||||
|
M_WINCH = 3 |
||||||
|
}; |
||||||
|
|
||||||
|
enum world_thing_kind { |
||||||
|
PLAYER_W = 0, |
||||||
|
FLOOR = 1, |
||||||
|
CEILING = 2, |
||||||
|
ROOM_W, |
||||||
|
STATIC_WALL_W,
|
||||||
|
PROJECTILE |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
// used to exert a force on an object
|
||||||
|
typedef struct motorstruct { |
||||||
|
double x; // positive is right
|
||||||
|
double y; // positive is down
|
||||||
|
double torque; // positive is anticlockwise
|
||||||
|
double max_velocity; // max motor output velocity
|
||||||
|
// does not apply force if the velocity in the
|
||||||
|
// direction of the motor vector is greater than
|
||||||
|
// max_velocity
|
||||||
|
|
||||||
|
struct timespec timeout;// absolute time (in ns, from when the program starts)
|
||||||
|
// for how long the motor runs before stopping
|
||||||
|
// automatically
|
||||||
|
// set to -1 for infinity
|
||||||
|
bool stop; // turn the motor off or on
|
||||||
|
void (*update_motor)(struct motorstruct *motor); // function pointer for generating
|
||||||
|
// the motor's output curve
|
||||||
|
struct BodyStruct *end_object; |
||||||
|
} Motor; |
||||||
|
|
||||||
|
typedef struct { |
||||||
|
int x; |
||||||
|
int y; |
||||||
|
} Point; |
||||||
|
|
||||||
|
/* String structure, used as a sub-element of a Body, compressible, but not
|
||||||
|
* stretchable. */ |
||||||
|
struct String { |
||||||
|
bool attached; |
||||||
|
double max_length; |
||||||
|
Vect end_point; |
||||||
|
int (*update_end_point)(struct String*); // method to update the end pt
|
||||||
|
// say if string is attached
|
||||||
|
// to another object
|
||||||
|
int (*set_end_point)(struct String*, Vect *); // manually set the end point of
|
||||||
|
// string
|
||||||
|
}; |
||||||
|
|
||||||
|
typedef struct String String; |
||||||
|
|
||||||
|
typedef struct BodyStruct{ |
||||||
|
// turn on dynamic physics
|
||||||
|
// For moving objects.
|
||||||
|
// eg. on for payer, off for walls
|
||||||
|
bool dynamics; |
||||||
|
|
||||||
|
// unique identifier
|
||||||
|
int uid; |
||||||
|
|
||||||
|
bool colliding; |
||||||
|
int was_colliding; |
||||||
|
|
||||||
|
// position in viewport (pixels)
|
||||||
|
SDL_Point screen_pos; |
||||||
|
SDL_mutex * lock; |
||||||
|
|
||||||
|
// SI Unit kinematics
|
||||||
|
/*------------------*/ |
||||||
|
Vect position; |
||||||
|
Vect next_position; // used for casting collision
|
||||||
|
Vect vel; |
||||||
|
Vect acc; |
||||||
|
|
||||||
|
// properties
|
||||||
|
double obj_mass; // kgs
|
||||||
|
double obj_elasticity; // rho
|
||||||
|
double obj_friction; // between 0 and 1 (fraction of lateral velocity
|
||||||
|
// that is removed)
|
||||||
|
|
||||||
|
//float x_vel;
|
||||||
|
//float y_vel;
|
||||||
|
|
||||||
|
//float x_acc;
|
||||||
|
//float y_acc;
|
||||||
|
/*------------------*/ |
||||||
|
|
||||||
|
// collisions
|
||||||
|
Vect *collision_poly; |
||||||
|
Vect *collision_shape; |
||||||
|
int collision_poly_size; |
||||||
|
int collision_shape_size; |
||||||
|
void (*updateCollisionPoly)(struct BodyStruct *); |
||||||
|
|
||||||
|
// fields
|
||||||
|
double glob_friction; |
||||||
|
bool glob_gravity; // t/f
|
||||||
|
|
||||||
|
// uint32_t last_advance_time;
|
||||||
|
|
||||||
|
struct timespec last_advance_time; |
||||||
|
|
||||||
|
// applying forces
|
||||||
|
int num_motors; |
||||||
|
int max_motors; |
||||||
|
Motor *motors; |
||||||
|
|
||||||
|
int num_strings; |
||||||
|
int max_strings; |
||||||
|
String *strings; |
||||||
|
|
||||||
|
} Body; |
||||||
|
|
||||||
|
typedef struct { |
||||||
|
bool has_physics; |
||||||
|
Body *physics; |
||||||
|
int max_walking_speed; |
||||||
|
int colliding; |
||||||
|
} player_st; |
||||||
|
|
||||||
|
typedef struct { |
||||||
|
int numNodes; |
||||||
|
SDL_Point *nodes; |
||||||
|
Body *physics; |
||||||
|
} Wall; |
||||||
|
|
||||||
|
typedef struct { |
||||||
|
Vect left; |
||||||
|
Vect right; |
||||||
|
Body *physics;
|
||||||
|
} FloorPoly; |
||||||
|
|
||||||
|
typedef struct { |
||||||
|
FloorPoly *polys; |
||||||
|
int numPolys; |
||||||
|
} Floor; |
||||||
|
|
||||||
|
struct physics_collection { |
||||||
|
int numItems; |
||||||
|
Body **items; |
||||||
|
}; |
||||||
|
|
||||||
|
typedef struct Projectile { |
||||||
|
Body *physics; |
||||||
|
void*(*on_collision)(struct Projectile*); |
||||||
|
void*(*on_step)(struct Projectile*); |
||||||
|
} Projectile; |
||||||
|
|
||||||
|
struct colour_pallete { |
||||||
|
struct colour bg; |
||||||
|
struct colour fg1; |
||||||
|
struct colour fg2; |
||||||
|
struct colour fg3; |
||||||
|
};
|
||||||
|
|
||||||
|
struct environment { |
||||||
|
int level; |
||||||
|
Vect position; |
||||||
|
ArrayList ceil; // doubles
|
||||||
|
ArrayList floor; // doubles
|
||||||
|
ArrayList bg1; // doubles
|
||||||
|
ArrayList bg2; // doubles
|
||||||
|
struct colour_pallete colours; |
||||||
|
struct physics_collection physics; |
||||||
|
}; |
||||||
|
|
||||||
|
struct room { |
||||||
|
struct environment env; |
||||||
|
struct physics_collection ceil; |
||||||
|
struct physics_collection floor; |
||||||
|
}; |
||||||
|
|
||||||
|
struct world_thing { |
||||||
|
enum world_thing_kind kind; |
||||||
|
int nid; |
||||||
|
bool collisions; |
||||||
|
bool physics; |
||||||
|
// free function for the below type
|
||||||
|
void (*free)(void *);
|
||||||
|
union { |
||||||
|
player_st *player; |
||||||
|
Wall *wall; |
||||||
|
Floor *floor; |
||||||
|
Projectile *projectile; |
||||||
|
struct room *room; |
||||||
|
}; |
||||||
|
}; |
||||||
|
|
||||||
|
typedef struct world_thing world_thing; |
||||||
|
|
||||||
|
struct world { |
||||||
|
world_thing (*get)(int i); |
||||||
|
ArrayList items; |
||||||
|
int modified; |
||||||
|
world_thing** uniques_index; |
||||||
|
}; |
||||||
|
|
||||||
|
typedef struct world GlobWorld; |
||||||
|
|
||||||
|
// environment
|
||||||
|
|
||||||
|
enum { |
||||||
|
// E_ROOM_WIDTH = 100000,
|
||||||
|
E_ROOM_WIDTH = 10000, |
||||||
|
E_ROOM_RES = 500, |
||||||
|
E_ROOM_TILES = E_ROOM_WIDTH / E_ROOM_RES, |
||||||
|
}; |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,81 @@ |
|||||||
|
#include "vect.h" |
||||||
|
|
||||||
|
double vect_dot(Vect V, Vect B) { |
||||||
|
return V.x * B.x + V.y * B.y; |
||||||
|
} |
||||||
|
|
||||||
|
double vect_mag(Vect v) { |
||||||
|
double mag = sqrt((v.x * v.x) + (v.y * v.y)); |
||||||
|
return mag; |
||||||
|
} |
||||||
|
|
||||||
|
Vect vect_scalar(Vect V, double s) { |
||||||
|
Vect ret; |
||||||
|
ret.x = V.x * s; |
||||||
|
ret.y = V.y * s; |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
double vect_arg(Vect v) { |
||||||
|
return atan2(v.y, v.x); |
||||||
|
} |
||||||
|
|
||||||
|
Vect vect_modarg(double mod, double arg) { |
||||||
|
Vect ret; |
||||||
|
ret.x = mod * cos(arg); |
||||||
|
ret.y = mod * sin(arg); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
Vect vect_rotate(Vect v, double radians) { |
||||||
|
Vect res; |
||||||
|
|
||||||
|
res.x = v.x * cos(radians) - v.y * sin(radians); |
||||||
|
res.y = v.x * sin(radians) + v.y * cos(radians); |
||||||
|
return res; |
||||||
|
} |
||||||
|
|
||||||
|
Vect vect_add(Vect v1, Vect v2) { |
||||||
|
Vect res; |
||||||
|
res.x = v1.x + v2.x; |
||||||
|
res.y = v1.y + v2.y; |
||||||
|
return res; |
||||||
|
} |
||||||
|
|
||||||
|
// project one onto two
|
||||||
|
Vect project_vect(Vect one, Vect two) { |
||||||
|
// $$ a \cdot \frac {|b|} {b} $$
|
||||||
|
Vect unittwo; |
||||||
|
unittwo.x = two.x / vect_mag(two); |
||||||
|
unittwo.y = two.y / vect_mag(two); |
||||||
|
|
||||||
|
Vect proj; |
||||||
|
proj.x = unittwo.x * one.x; |
||||||
|
proj.y = unittwo.y * one.y; |
||||||
|
|
||||||
|
return proj; |
||||||
|
} |
||||||
|
|
||||||
|
// project V onto P
|
||||||
|
double old_vect_scalar_projection(Vect V, Vect P) { |
||||||
|
double angle = vect_dir(V) - vect_dir(P); |
||||||
|
return cos(angle) * vect_mag(V); |
||||||
|
} |
||||||
|
|
||||||
|
double vect_scalar_projection(Vect v, Vect p) { |
||||||
|
double num = vect_dot(v, p); |
||||||
|
return num / vect_mag(p); |
||||||
|
} |
||||||
|
|
||||||
|
double vect_dir(Vect V) { |
||||||
|
return atan2(V.y, V.x); |
||||||
|
} |
||||||
|
|
||||||
|
// distance between two points
|
||||||
|
double vect_distance(Vect A, Vect B) { |
||||||
|
double y = (B.y - A.y); |
||||||
|
double x = (B.x - A.x); |
||||||
|
y = y * y; |
||||||
|
x = x * x; |
||||||
|
return sqrt(x + y); |
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
|
||||||
|
#ifndef VECT_H |
||||||
|
#define VECT_H |
||||||
|
#include <math.h> |
||||||
|
|
||||||
|
// origin-centred vector
|
||||||
|
typedef struct { |
||||||
|
double x; |
||||||
|
double y; |
||||||
|
} Vect; |
||||||
|
|
||||||
|
/* Return the magnitude of two vectors */ |
||||||
|
double vect_mag(Vect v);
|
||||||
|
|
||||||
|
/* Return the angle of a vector in radians (using atan2) */ |
||||||
|
double vect_dir(Vect V); |
||||||
|
|
||||||
|
/* Return the dot product of two vectors */ |
||||||
|
double vect_dot(Vect V, Vect B);
|
||||||
|
|
||||||
|
/* return a vector multiplied by a scalar */ |
||||||
|
Vect vect_scalar(Vect V, double s); |
||||||
|
|
||||||
|
/* Return the sum of two vectors */ |
||||||
|
Vect vect_add(Vect v1, Vect v2);
|
||||||
|
|
||||||
|
/* Return the projection of vector one onto vector two */ |
||||||
|
Vect project_vect(Vect one, Vect two);
|
||||||
|
|
||||||
|
/* Return the scalar projection of V onto P */ |
||||||
|
double vect_scalar_projection(Vect V, Vect P);
|
||||||
|
|
||||||
|
/* Return the vector v rotated by radians radians. */ |
||||||
|
Vect vect_rotate(Vect v, double radians); |
||||||
|
|
||||||
|
/* Return the argument of v in radians */ |
||||||
|
double vect_arg(Vect v); |
||||||
|
|
||||||
|
/* create a vector using modarg form */ |
||||||
|
Vect vect_modarg(double mod, double arg);
|
||||||
|
|
||||||
|
/* Return the distance between two point vectors A and B */ |
||||||
|
double vect_distance(Vect A, Vect B);
|
||||||
|
|
||||||
|
#endif |
Loading…
Reference in new issue