Unverified Commit 7d1d364d authored by Rob Loach's avatar Rob Loach Committed by GitHub
Browse files

Merge pull request #289 from libretro/dev

0.25.0
parents 954de841 6d496b0e
......@@ -4,3 +4,4 @@
node_modules
*.srm.*
*.srm1.*
/package.json
......@@ -43,6 +43,13 @@ cache:
directories:
- vendor
# Only build on master and dev branches
# Others are handled by Pull Requests
branches:
only:
- master
- dev
notifications:
on_success: false
email: false
......@@ -4,6 +4,17 @@ All notable changes to [ChaiLove](https://github.com/RobLoach/ChaiLove) will be
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## 0.25.0 - 2018-09-08
### Features
- Added Cheat support
- `cheatset(index, enabled, code)`
- `cheatreset()`
- Added `.ogg` audio support
### Fixes
- Fixed save state loading
- Fixed `love.filesystem.mount()` logic
## 0.24.0 - 2018-09-03
### Features
- Update to use libretro-common audio
......
......@@ -72,7 +72,9 @@ docs-clean:
rm -rf docs/html
docs-deploy: docs
npm install push-dir && node_modules/.bin/push-dir --dir=docs/html --branch=docs
npm init --force -y
npm install push-dir
node_modules/.bin/push-dir --dir=docs/html --branch=docs
cpplint: vendor/libretro-common/include/libretro.h
@vendor/styleguide/cpplint/cpplint.py \
......
# Appveyor Config
ifeq ($(appveyor),1)
FLAGS += -DPRId64=I64d -DPRIu64=I64u -DPRIuPTR=Iu
endif
# ChaiLove
SOURCES_CXX := $(wildcard \
$(CORE_DIR)/src/*.cpp \
......@@ -39,6 +44,9 @@ SOURCES_C += $(wildcard \
$(CORE_DIR)/vendor/libretro-common/file/config_file_userdata.c \
$(CORE_DIR)/vendor/libretro-common/file/file_path.c \
$(CORE_DIR)/vendor/libretro-common/compat/compat_strl.c \
$(CORE_DIR)/vendor/libretro-common/compat/fopen_utf8.c \
$(CORE_DIR)/vendor/libretro-common/compat/compat_posix_string.c \
$(CORE_DIR)/vendor/libretro-common/encodings/encoding_utf.c \
$(CORE_DIR)/vendor/libretro-common/file/config_file_userdata.c \
$(CORE_DIR)/vendor/libretro-common/file/config_file.c \
$(CORE_DIR)/vendor/libretro-common/lists/string_list.c \
......@@ -46,6 +54,11 @@ SOURCES_C += $(wildcard \
$(CORE_DIR)/vendor/libretro-common/lists/string_list.c \
)
# stb_vorbis
#SOURCES_C += $(CORE_DIR)/vendor/stb/stb_vorbis.c
FLAGS += -DHAVE_STB_VORBIS
FLAGS += -I$(CORE_DIR)/vendor/libretro-deps
# zlib
SOURCES_C += \
$(CORE_DIR)/vendor/libretro-deps/libz/zutil.c \
......
......@@ -28,8 +28,8 @@ ChaiLove is a [libretro](https://www.libretro.com/) core, which can be run throu
Alternatively, you can run the ChaiLove core through RetroArch via the command line:
```
wget https://buildbot.libretro.com/assets/cores/ChaiLove/Floppy%20Bird.chailove
retroarch -L chailove_libretro.so Floppy\ Bird.chailove
wget https://github.com/RobLoach/ChaiLove-FloppyBird/releases/download/0.20.0/FloppyBird.chailove
retroarch -L chailove_libretro.so FloppyBird.chailove
```
## API
......@@ -60,9 +60,11 @@ To run it, execute the following:
retroarch -L chailove_libretro.so main.chai
```
See the [ChaiLove API](https://rawgit.com/libretro/libretro-chailove/docs/) for coverage of all the callbacks and methods in ChaiLove.
## Development
Behind ChaiLove, there's the [documentation](#documentation), [compiling it](#compiling), along with [testing](#testing).
The following are some notes about the development process behind ChaiLove.
### Compiling
......
......@@ -2,10 +2,12 @@
# https://ci.appveyor.com/project/RobLoach/libretro-chailove
version: '{build}'
# Don't build the Documentation
# Build branches master and dev
# The others are done via Pull Requests
branches:
except:
- docs
only:
- master
- dev
skip_tags: true
skip_non_tags: false
......@@ -17,6 +19,7 @@ environment:
TARGET: chailove_libretro.dll
platform: win
system_platform: win
appveyor: 1
init:
- git config --global core.autocrlf input
......@@ -32,7 +35,7 @@ before_build:
- gcc --version
build_script:
- make
- make appveyor=1
# TODO: Add automated testing
#before_test:
......
......@@ -23,7 +23,7 @@ PROJECT_NAME = "ChaiLove API"
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER = "0.24.0"
PROJECT_NUMBER = "0.25.0"
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
......
......@@ -240,3 +240,21 @@ bool ChaiLove::loadstate(const std::string& data) {
}
return false;
}
/**
* Invoke the script cheatreset hook.
*/
void ChaiLove::cheatreset() {
if (script != NULL) {
script->cheatreset();
}
}
/**
* Invoke the script cheatset hook.
*/
void ChaiLove::cheatset(int index, bool enabled, const std::string& code) {
if (script != NULL) {
script->cheatset(index, enabled, code);
}
}
......@@ -47,9 +47,9 @@
#define SRC_CHAILOVE_H_
#define CHAILOVE_VERSION_MAJOR 0
#define CHAILOVE_VERSION_MINOR 24
#define CHAILOVE_VERSION_MINOR 25
#define CHAILOVE_VERSION_PATCH 0
#define CHAILOVE_VERSION_STRING "0.24.0"
#define CHAILOVE_VERSION_STRING "0.25.0"
#include "SDL.h"
#include "libretro.h"
......@@ -111,6 +111,8 @@ class ChaiLove {
void reset();
std::string savestate();
bool loadstate(const std::string& data);
void cheatreset();
void cheatset(int index, bool enabled, const std::string& code);
uint32_t *videoBuffer = NULL;
SDL_Surface* screen = NULL;
......
......@@ -36,7 +36,7 @@ extern "C" {
#endif
void libretro_audio_cb(int16_t left, int16_t right) {
// Nothing?
// Nothing, since we're using libretro-common.
// audio_cb(left, right);
}
......@@ -285,16 +285,19 @@ bool retro_unserialize(const void *data, size_t size) {
* libretro callback; Reset the enabled cheats.
*/
void retro_cheat_reset(void) {
// Nothing.
if (ChaiLove::hasInstance()) {
ChaiLove::getInstance()->cheatreset();
}
}
/**
* libretro callback; Set the given cheat.
*/
void retro_cheat_set(unsigned index, bool enabled, const char *code) {
(void)index;
(void)enabled;
(void)code;
if (ChaiLove::hasInstance()) {
std::string codeString(code);
ChaiLove::getInstance()->cheatset(index, enabled, codeString);
}
}
/**
......
#include "SoundData.h"
#include <string>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
......@@ -12,23 +11,39 @@ namespace Types {
namespace Audio {
SoundData::SoundData(const std::string& filename) {
// Load the file.
// Check the extension.
ChaiLove* app = ChaiLove::getInstance();
std::string extension = app->filesystem.newFileData(filename).getExtension();
if (extension != "wav" && extension != "ogg") {
std::cout << "[ChaiLove] [SoundData] Unknown extension " << extension << " for file " << filename << "." << std::endl;
return;
}
// Load the file.
int size = 0;
void* buffer = app->filesystem.readBuffer(filename, size);
buffer = app->filesystem.readBuffer(filename, size);
if (buffer == NULL) {
std::cout << "[ChaiLove] [SoundData] Failed to load file buffer " << filename << std::endl;
std::cout << "[ChaiLove] [SoundData] Failed to load file " << filename << std::endl;
return;
}
// Load the file into the buffer.
// TODO(RobLoach): Check the audio file extensions of ".wav".
m_sound = audio_mixer_load_wav(buffer, size);
free(buffer);
// Load the audio from the file.
if (extension == "wav") {
m_sound = audio_mixer_load_wav(buffer, size);
// Wav files don't need the buffer anymore.
free(buffer);
buffer = NULL;
} else if (extension == "ogg") {
m_sound = audio_mixer_load_ogg(buffer, size);
}
// Finally, if it failed, report as such.
if (m_sound == NULL) {
std::cout << "[ChaiLove] [SoundData] Failed to load wav from buffer " << filename << std::endl;
std::cout << "[ChaiLove] [SoundData] Failed to load audio for " << filename << std::endl;
if (buffer != NULL) {
free(buffer);
buffer = NULL;
}
}
}
......@@ -61,8 +76,9 @@ SoundData& SoundData::setVolume(float volume) {
void SoundData::unload() {
if (m_voice != NULL) {
audio_mixer_stop(m_voice);
m_voice = NULL;
}
if (isLoaded()) {
if (m_sound != NULL) {
audio_mixer_destroy(m_sound);
m_sound = NULL;
}
......
......@@ -2,7 +2,6 @@
#define SRC_LOVE_TYPES_AUDIO_SOUNDDATA_H_
#include <string>
#include "physfs.h"
#include "audio/audio_mixer.h"
namespace love {
......@@ -34,6 +33,8 @@ class SoundData {
* Gets the current volume of the Source.
*
* @return The volume of the source, from 0.0f to 1.0f.
*
* @see setVolume
*/
float getVolume();
......@@ -43,6 +44,8 @@ class SoundData {
* @param volume The volume to set the source at, from 0.0f to 1.0f.
*
* @return The SoundData object iself, to allow for method chaining.
*
* @see getVolume
*/
SoundData& setVolume(float volume);
......@@ -55,24 +58,29 @@ class SoundData {
/**
* Returns whether the Source will loop.
*
* @see setLooping
*/
bool isLooping();
/**
* Set whether the Source should loop.
*
* @see isLooping
*/
SoundData& setLooping(bool loop);
// The audio callback for when a sound finishes.
static void audioCallback(audio_mixer_sound_t* sound, unsigned reason);
// Properties
bool m_playing = false;
bool m_loop = false;
float m_volume = 1.0f;
void* buffer = NULL;
audio_mixer_sound* m_sound = NULL;
// TODO(RobLoach): Make voice a vector.
// TODO(RobLoach): Make voice a vector?
audio_mixer_voice_t* m_voice = NULL;
// The audio callback for when a sound finishes.
static void audioCallback(audio_mixer_sound_t* sound, unsigned reason);
};
} // namespace Audio
......
......@@ -25,11 +25,15 @@ class Image {
/**
* Gets the width of the Texture.
*
* @see getHeight
*/
int getWidth();
/**
* Gets the height of the Texture.
*
* @see getWidth
*/
int getHeight();
};
......
......@@ -10,6 +10,8 @@ namespace love {
/**
* Provides an interface to output sound to the user's speakers.
*
* @see love.sound
*/
class audio {
public:
......@@ -29,6 +31,8 @@ class audio {
* @param type ("static") The type of audio source to load ("static", "stream"). Optional.
*
* @return The new SoundData if it loaded correctly, NULL otherwise.
*
* @see love.sound.newSoundData
*/
SoundData* newSource(const std::string& filename, const std::string& type);
SoundData* newSource(const std::string& filename);
......
......@@ -19,7 +19,7 @@ namespace love {
*
* @code
* def conf(t) {
* t.version = "0.24.0" // Version of ChaiLove
* t.version = "0.25.0" // Version of ChaiLove
* t.identity = "mygame" // Machine name of your game
* t.window.title = "My Game" // Human-readable name
* t.window.width = 1024 // Game width
......
......@@ -54,14 +54,14 @@ bool filesystem::init(const std::string& file) {
void filesystem::mountlibretro() {
// Mount some of the libretro directories.
const char *system_dir = NULL;
const char *assets_dir = NULL;
const char *save_dir = NULL;
if (ChaiLove::environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &system_dir) && system_dir) {
mount(system_dir, "libretro/system");
}
const char *content_dir = NULL;
if (ChaiLove::environ_cb(RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY, &content_dir) && content_dir) {
mount(content_dir, "libretro/assets");
if (ChaiLove::environ_cb(RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY, &assets_dir) && assets_dir) {
mount(assets_dir, "libretro/assets");
}
const char *save_dir = NULL;
if (ChaiLove::environ_cb(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &save_dir) && save_dir) {
save_dir = *save_dir ? save_dir : system_dir;
mount(save_dir, "libretro/saves");
......@@ -214,7 +214,19 @@ bool filesystem::unmount(const std::string& archive) {
return true;
}
bool filesystem::mount(const char *archive, const std::string& mountpoint) {
// Allow mounting character pointers safely.
if (archive == NULL) {
return false;
}
return mount(std::string(archive), mountpoint);
}
bool filesystem::mount(const std::string& archive, const std::string& mountpoint) {
// Protect against empty archive/mount points.
if (archive.length() <= 0 || mountpoint.length() <= 0) {
return false;
}
std::cout << "[ChaiLove] [filesystem] Mounting " << archive << " as " << mountpoint << std::endl;
int returnValue = PHYSFS_mount(archive.c_str(), mountpoint.c_str(), 0);
if (returnValue == 0) {
......
......@@ -106,6 +106,8 @@ class filesystem {
* @param archive The archive that was previously mounted with love.filesystem.mount.
*
* @return bool True, when unmounting was a success.
*
* @see mount
*/
bool unmount(const std::string& archive);
......@@ -113,8 +115,11 @@ class filesystem {
* Mounts a zip file or folder in the game's save directory for reading.
*
* @return bool True, when mounting was a success.
*
* @see unmount
*/
bool mount(const std::string& archive, const std::string& mountpoint);
bool mount(const char *archive, const std::string& mountpoint);
PHYSFS_sint64 getSize(PHYSFS_File* file);
PHYSFS_file* openFile(const std::string& filename);
......@@ -126,16 +131,25 @@ class filesystem {
/**
* Check whether something is a directory.
*
* @see isFile
* @see isSymlink
*/
bool isDirectory(const std::string& filename);
/**
* Checks whether something is a file.
*
* @see isDirectory
* @see isSymlink
*/
bool isFile(const std::string& filename);
/**
* Checks whether something is a symlink.
*
* @see isDirectory
* @see isFile
*/
bool isSymlink(const std::string& filename);
......@@ -167,6 +181,8 @@ class filesystem {
* @param delimiter ("\n") A string of characters representing what would be considered a new line.
*
* @return A vector array of strings representing all the lines in the given file.
*
* @see read
*/
std::vector<std::string> lines(const std::string& filename, const std::string& delimiter);
std::vector<std::string> lines(const std::string& filename);
......
......@@ -6,6 +6,8 @@
namespace love {
/**
* Allows you to work with fonts.
*
* @see love.graphics.newFont
*/
class font {
public:
......@@ -16,6 +18,8 @@ class font {
* Retrieves whether or not all sub-systems have been loaded.
*
* @return True if the Font sub-system has been loaded.
*
* @see love.graphics.newFont
*/
bool isOpen();
......
......@@ -279,7 +279,7 @@ script::script(const std::string& file) {
chai.add(fun(&filesystem::getInfo), "getInfo");
chai.add(fun(&filesystem::newFileData), "newFileData");
chai.add(fun(&filesystem::getDirectoryItems), "getDirectoryItems");
chai.add(fun(&filesystem::mount), "mount");
chai.add(fun<bool, filesystem, const std::string&, const std::string&>(&filesystem::mount), "mount");
chai.add(fun<int, filesystem, const std::string&>(&filesystem::getSize), "getSize");
chai.add(fun<std::vector<std::string>, filesystem, const std::string&>(&filesystem::lines), "lines");
chai.add(fun<std::vector<std::string>, filesystem, const std::string&, const std::string&>(&filesystem::lines), "lines");
......@@ -462,7 +462,7 @@ script::script(const std::string& file) {
haskeyreleased = false;
}
try {
chailoadstate = chai.eval<std::function<bool(std::string)> >("loadstate");
chailoadstate = chai.eval<std::function<bool(const std::string&)> >("loadstate");
}
catch (const std::exception& e) {
std::cout << "[ChaiLove] [script] loadstate() " << e.what() << std::endl;
......@@ -475,6 +475,20 @@ script::script(const std::string& file) {
std::cout << "[ChaiLove] [script] savestate() " << e.what() << std::endl;
hassavestate = false;
}
try {
chaicheatreset = chai.eval<std::function<void()> >("cheatreset");
}
catch (const std::exception& e) {
std::cout << "[ChaiLove] [script] cheatreset() Warning: " << e.what() << std::endl;
hascheatreset = false;
}
try {
chaicheatset = chai.eval<std::function<void(int, bool, const std::string&)> >("cheatset");
}
catch (const std::exception& e) {
std::cout << "[ChaiLove] [script] cheatset() Warning: " << e.what() << std::endl;
hascheatset = false;
}
try {
chaiexit = chai.eval<std::function<void()> >("exit");
}
......@@ -695,6 +709,34 @@ bool script::loadstate(const std::string& data) {
return false;
}
void script::cheatreset() {
#ifdef __HAVE_CHAISCRIPT__
if (hascheatreset) {
try {
chaicheatreset();
}
catch (const std::exception& e) {
std::cout << "[ChaiLove] [script] Failed to call cheatreset(): " << e.what() << std::endl;
hascheatreset = false;
}
}
#endif
}
void script::cheatset(int index, bool enabled, const std::string& code) {
#ifdef __HAVE_CHAISCRIPT__
if (hascheatreset) {
try {
chaicheatset(index, enabled, code);
}
catch (const std::exception& e) {
std::cout << "[ChaiLove] [script] Failed to call cheatset(): " << e.what() << std::endl;
hascheatset = false;
}
}
#endif
}
void script::exit() {
#ifdef __HAVE_CHAISCRIPT__
if (hasexit) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment