alistair
3 years ago
43 changed files with 5308 additions and 0 deletions
@ -0,0 +1,25 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -0,0 +1,3 @@
|
||||
distribution/ |
||||
.gradle/ |
||||
.idea/ |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
.externalNativeBuild/ |
@ -0,0 +1,38 @@
@@ -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 @@
@@ -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 @@
@@ -0,0 +1 @@
|
||||
.externalNativeBuild/ |
@ -0,0 +1,45 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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,2 @@
@@ -0,0 +1,2 @@
|
||||
|
||||
#define SHOWCOLLISIONBOX 1 |
@ -0,0 +1,881 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -0,0 +1,2 @@
|
||||
#include "physics.h" |
||||
#include "types.h" |
@ -0,0 +1,236 @@
@@ -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 @@
@@ -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 @@
@@ -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