Commit f1c5c073 authored by Gerhard Stein's avatar Gerhard Stein

Ressource compiler and automatic catalogue downloader

parent cff5c74a
......@@ -809,7 +809,8 @@ void CInput::pollEvents()
dispRect.h = Event.resize.h;
break;
#endif
/*
#ifndef ANDROID
case SDL_MOUSEBUTTONDOWN:
if(Event.button.button <= 3)
......@@ -881,7 +882,7 @@ void CInput::pollEvents()
gPointDevice.mPointingState.mPos = Pos;
break;
*/
#endif
}
if(passSDLEventVec)
......
......@@ -45,6 +45,14 @@ public:
*/
bool loadPicture(const std::string &picFile);
/**
* @brief loadEmdbeddedPicture Load picture from internal memory
* @param data
* @return
*/
bool loadEmdbeddedPicture(const unsigned char *data,
const unsigned int size);
stInputCommand* cmd = nullptr;
......
......@@ -500,7 +500,7 @@ void InitBaseSearchPaths() {
#else // all other systems (Linux, *BSD, OS/2, ...)
#ifdef ANDROID
//AddToFileList(&basesearchpaths, "${HOME}/SaveData");
AddToFileList(&basesearchpaths, "/storage/emulated/0/Android/data/net.sourceforge.clonekeenplus/files/SaveData");
AddToFileList(&basesearchpaths, "/storage/emulated/0/Android/data/net.sourceforge.clonekeenplusplus/files/SaveData");
#else
AddToFileList(&basesearchpaths, "${HOME}/.CommanderGenius");
#endif
......
......@@ -67,6 +67,41 @@ public:
return (mpTexture!=nullptr);
}
/**
* @brief loadFromMem Will try to load the texture
* @param data pointer from where to load it
* @renderer renderer on which the texture will be drawn
* @return true if it was loaded, otherwise false
*/
bool loadFromMem(const unsigned char *data,
const unsigned int size,
SDL_Renderer *renderer)
{
// Do we have an old texture? Unload it
if(mpTexture)
unload();
SDL_RWops *rw = SDL_RWFromMem((void*)data, size);
// Load image at specified path
SDL_Surface* loadedSurface = IMG_Load_RW(rw, 1);
if( loadedSurface )
{
//Create texture from surface pixels
mpTexture = SDL_CreateTextureFromSurface( renderer, loadedSurface );
if( mpTexture == nullptr )
{
//printf( "Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError() );
}
// Get rid of old surface
SDL_FreeSurface( loadedSurface );
}
return (mpTexture!=nullptr);
}
//Set blending
void setBlendMode( SDL_BlendMode blending )
{
......
......@@ -12,12 +12,12 @@ android {
buildToolsVersion '27.0.3'
defaultConfig {
if (buildAsApplication) {
applicationId "org.libsdl.app"
applicationId "net.sourceforge.clonekeenplus"
}
minSdkVersion 14
targetSdkVersion 19
versionCode 1
versionName "1.0"
versionCode 22300
versionName '2.2.3'
externalNativeBuild {
ndkBuild {
arguments "APP_PLATFORM=android-14"
......@@ -40,29 +40,36 @@ android {
path 'jni/Android.mk'
}
}
}
lintOptions {
abortOnError false
}
if (buildAsLibrary) {
libraryVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith(".aar")) {
def fileName = "org.libsdl.app.aar";
def fileName = "net.sourceforge.clonekeenplus.aar";
output.outputFile = new File(outputFile.parent, fileName);
}
}
}
}
productFlavors {
}
sourceSets {
main {
assets.srcDirs = ['src/main/assets']
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
implementation fileTree(include: ['*.jar'], dir: 'libs')
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
testCompile 'junit:junit:4.12'
testImplementation 'junit:junit:4.12'
}
......@@ -3,9 +3,9 @@
com.gamemaker.game
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.libsdl.app"
android:versionCode="1"
android:versionName="1.0"
package="net.sourceforge.clonekeenplus"
android:versionCode="22000"
android:versionName="2.2.3"
android:installLocation="auto">
<!-- Android 4.0.1 -->
......
package org.libsdl.app;
import android.content.Context;
/**
SDL library initialization
*/
public class SDL {
// This function should be called first and sets up the native code
// so it can call into the Java classes
public static void setupJNI() {
SDLActivity.nativeSetupJNI();
SDLAudioManager.nativeSetupJNI();
SDLControllerManager.nativeSetupJNI();
}
// This function should be called each time the activity is started
public static void initialize() {
setContext(null);
SDLActivity.initialize();
SDLAudioManager.initialize();
SDLControllerManager.initialize();
}
// This function stores the current activity (SDL or not)
public static void setContext(Context context) {
mContext = context;
}
public static Context getContext() {
return mContext;
}
protected static Context mContext;
}
package org.libsdl.app;
import android.media.*;
import android.util.Log;
public class SDLAudioManager
{
protected static final String TAG = "SDLAudio";
protected static AudioTrack mAudioTrack;
protected static AudioRecord mAudioRecord;
public static void initialize() {
mAudioTrack = null;
mAudioRecord = null;
}
// Audio
/**
* This method is called by SDL using JNI.
*/
public static int audioOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
Log.v(TAG, "SDL audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
// Let the user pick a larger buffer if they really want -- but ye
// gods they probably shouldn't, the minimums are horrifyingly high
// latency already
desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
if (mAudioTrack == null) {
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
// Instantiating AudioTrack can "succeed" without an exception and the track may still be invalid
// Ref: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/AudioTrack.java
// Ref: http://developer.android.com/reference/android/media/AudioTrack.html#getState()
if (mAudioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
Log.e(TAG, "Failed during initialization of Audio Track");
mAudioTrack = null;
return -1;
}
mAudioTrack.play();
}
Log.v(TAG, "SDL audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
return 0;
}
/**
* This method is called by SDL using JNI.
*/
public static void audioWriteShortBuffer(short[] buffer) {
if (mAudioTrack == null) {
Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
return;
}
for (int i = 0; i < buffer.length; ) {
int result = mAudioTrack.write(buffer, i, buffer.length - i);
if (result > 0) {
i += result;
} else if (result == 0) {
try {
Thread.sleep(1);
} catch(InterruptedException e) {
// Nom nom
}
} else {
Log.w(TAG, "SDL audio: error return from write(short)");
return;
}
}
}
/**
* This method is called by SDL using JNI.
*/
public static void audioWriteByteBuffer(byte[] buffer) {
if (mAudioTrack == null) {
Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
return;
}
for (int i = 0; i < buffer.length; ) {
int result = mAudioTrack.write(buffer, i, buffer.length - i);
if (result > 0) {
i += result;
} else if (result == 0) {
try {
Thread.sleep(1);
} catch(InterruptedException e) {
// Nom nom
}
} else {
Log.w(TAG, "SDL audio: error return from write(byte)");
return;
}
}
}
/**
* This method is called by SDL using JNI.
*/
public static int captureOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
Log.v(TAG, "SDL capture: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
// Let the user pick a larger buffer if they really want -- but ye
// gods they probably shouldn't, the minimums are horrifyingly high
// latency already
desiredFrames = Math.max(desiredFrames, (AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
if (mAudioRecord == null) {
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate,
channelConfig, audioFormat, desiredFrames * frameSize);
// see notes about AudioTrack state in audioOpen(), above. Probably also applies here.
if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
Log.e(TAG, "Failed during initialization of AudioRecord");
mAudioRecord.release();
mAudioRecord = null;
return -1;
}
mAudioRecord.startRecording();
}
Log.v(TAG, "SDL capture: got " + ((mAudioRecord.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioRecord.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioRecord.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
return 0;
}
/** This method is called by SDL using JNI. */
public static int captureReadShortBuffer(short[] buffer, boolean blocking) {
// !!! FIXME: this is available in API Level 23. Until then, we always block. :(
//return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
return mAudioRecord.read(buffer, 0, buffer.length);
}
/** This method is called by SDL using JNI. */
public static int captureReadByteBuffer(byte[] buffer, boolean blocking) {
// !!! FIXME: this is available in API Level 23. Until then, we always block. :(
//return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
return mAudioRecord.read(buffer, 0, buffer.length);
}
/** This method is called by SDL using JNI. */
public static void audioClose() {
if (mAudioTrack != null) {
mAudioTrack.stop();
mAudioTrack.release();
mAudioTrack = null;
}
}
/** This method is called by SDL using JNI. */
public static void captureClose() {
if (mAudioRecord != null) {
mAudioRecord.stop();
mAudioRecord.release();
mAudioRecord = null;
}
}
public static native int nativeSetupJNI();
}
......@@ -74,10 +74,7 @@ m_start_level(start_level)
}
CGameLauncher::~CGameLauncher()
{
// The virtual pad must not exist anymore!
gInput.mpVirtPad = nullptr;
}
{}
////
// Initialization Routine
......@@ -466,8 +463,7 @@ bool CGameLauncher::start()
return 1;
}
};
};
mGameScanner.setStyle(PROGRESS_STYLE_TEXT);
mGameScanner.RunLoadActionBackground(new GamesScan(*this));
......
......@@ -6,6 +6,22 @@
#include <base/GsLogging.h>
#include <fileio/ResourceMgmt.h>
#include "dpad.h"
#include "button1.h"
#include "button2.h"
#include "button3.h"
#include "button4.h"
#include "buttonBg.h"
#include "buttonConfirm.h"
#include "buttonStart.h"
bool TouchButton::loadEmdbeddedPicture(const unsigned char *data,
const unsigned int size)
{
return mTexture.loadFromMem(data, size,
gVideoDriver.Renderer());
}
bool TouchButton::loadPicture(const std::string &picFile)
{
......@@ -29,53 +45,39 @@ VirtualKeenControl::~VirtualKeenControl()
bool VirtualKeenControl::init()
{
#if SDL_VERSION_ATLEAST(2, 0, 0)
/*GsWeakSurface blit(gVideoDriver.getBlitSurface());
SDL_PixelFormat *format = blit.getSDLSurface()->format;
const int buttonSize = 50;*/
// Create the overlay surface and fill it with alpha 0
/*
mOverlay.create(0, blit.width(), blit.height(), 32, 0, 0, 0, 0);
mOverlay.setBlendMode(SDL_BLENDMODE_BLEND);
mOverlay.setAlpha(uint8_t(255.0f*mTranslucency));
mOverlay.fill(SDL_MapRGBA(format, 0, 0, 0, 0 ));
/// Draw a D-Pad
// Left arrow
const GsRect<Uint16> upRect(0, blit.height()-buttonSize, buttonSize, buttonSize);
mOverlay.fill(upRect, SDL_MapRGBA(format, 128, 0, 0, 128 ));
*/
// Check if the virtual game pad image exist. If not download the picture package
/*if(!checkVPadImage())
{
downloadVPadImages();
extractVPadImages();
}
*/
/// Load The buttons images
{
// Start with the Background for the gamepad
if(!mPadBackground.loadPicture("bckgrnd.png")) return false;
if(!mPadBackground.loadEmdbeddedPicture(gButtonBgPng, sizeof(gButtonBgPng))) return false;
// Directional pad
if(!mDPad.loadPicture("dpad.png")) return false;
if(!mDPad.loadEmdbeddedPicture(gDPadPng, sizeof(gDPadPng))) return false;
if(!mConfirmButton.loadPicture("confirm.png")) return false;
if(!mConfirmButton.loadEmdbeddedPicture(gButtonConfirmPng, sizeof(gButtonConfirmPng))) return false;
mConfirmButton.invisible = false;
if(!mStartButton.loadPicture("start.png")) return false;
if(!mStartButton.loadEmdbeddedPicture(gButtonStartPng, sizeof(gButtonStartPng))) return false;
mStartButton.invisible = true;
if(!mJumpButton.loadPicture("1.png")) return false;
if(!mJumpButton.loadEmdbeddedPicture(gButton1Png, sizeof(gButton1Png))) return false;
mJumpButton.invisible = true;
if(!mPogoButton.loadPicture("2.png")) return false;
if(!mPogoButton.loadEmdbeddedPicture(gButton2Png, sizeof(gButton2Png))) return false;
mPogoButton.invisible = true;
if(!mShootButton.loadPicture("3.png")) return false;
if(!mShootButton.loadEmdbeddedPicture(gButton3Png, sizeof(gButton3Png))) return false;
mShootButton.invisible = true;
if(!mStatusButton.loadPicture("4.png")) return false;
if(!mStatusButton.loadEmdbeddedPicture(gButton4Png, sizeof(gButton4Png))) return false;
mStatusButton.invisible = true;
}
......
......@@ -21,25 +21,36 @@ void CGameLauncher::verifyGameStore()
std::vector< std::string > missingList;
// First try
gameDownloader.checkForMissingGames( missingList );
if(!gameDownloader.hasCatalog())
{
std::stringstream ss;
const auto cataFile = gameDownloader.catalogFName();
const auto searchPath = GetFirstSearchPath();
ss << "You seem not to have a game catalog.\n";
ss << "The file is called " << "\"" << cataFile << "\" \n";
ss << "You might want to download \n";
ss << "and copy one into:\n";
ss << "\"" << searchPath << "\".\n";
ss << "\"+ More\" button is disabled...\n";
std::string msg(ss.str());
showMessageBox(msg);
{
// Try to download the catalogue file
if(gameDownloader.downloadCatalogue())
{
gameDownloader.checkForMissingGames( missingList );
}
if(!gameDownloader.hasCatalog())
{
std::stringstream ss;
const auto cataFile = gameDownloader.catalogFName();
const auto searchPath = GetFirstSearchPath();
ss << "You seem not to have a game catalog.\n";
ss << "The file is called " << "\"" << cataFile << "\" \n";
ss << "You might want to download \n";
ss << "and copy one into:\n";
ss << "\"" << searchPath << "\".\n";
ss << "\"+ More\" button is disabled...\n";
std::string msg(ss.str());
showMessageBox(msg);
}
}
......
......@@ -8,6 +8,8 @@
#include <curl/curl.h>
#include <SDL_image.h>
#include <fileio/KeenFiles.h>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
......@@ -188,6 +190,9 @@ bool GameDownloader::loadCatalogue(const std::string &catalogueFile)
try
{
// Load the XML file into the property tree. If reading fails
// (cannot open file, parse error), an exception is thrown.
read_xml(catalogueFile, pt);
......@@ -225,10 +230,20 @@ bool GameDownloader::loadCatalogue(const std::string &catalogueFile)
return true;
}
#include <fileio/KeenFiles.h>
bool GameDownloader::downloadCatalogue()
{
pCancelDownload = &mCancelDownload;
const int res = downloadFile(mCatalogFName, mProgress, "");
if(res==0)
return true;
return false;
}
bool GameDownloader::checkForMissingGames( std::vector< std::string > &missingList )
{
{
// Load game catalogue
if( !loadCatalogue(mCatalogFName) )
{
......@@ -276,6 +291,7 @@ bool GameDownloader::checkForMissingGames( std::vector< std::string > &missingLi
mCataFound = true;
}
if(!mCataFound)
{
gLogging.ftextOut("Sorry, the catalogue file \"%s\" was not found <br>", mCatalogFName.c_str() );
......
......@@ -19,7 +19,6 @@ struct GameCatalogueEntry
};
class GameDownloader : public Action
{
public:
......@@ -46,6 +45,13 @@ public:
*/
bool loadCatalogue(const std::string &catalogueFile);
/**
* @brief downloadCatalogue Download the missing catalogue file
* @return
*/
bool downloadCatalogue();
/**
* @brief checkForMissingGames Test if there are games that the user does not have yet.
* @param missingList
......
#include <stdio.h>
/**
* @brief compileBinIntoCharArray Given a file generates a char array
* that can be used in the main sources
* @param filename
* @param output
*/
void compileBinIntoCharArray(const char *filename,
const char *globVar,
const char *output)
{
FILE *file = fopen(filename, "rb");
FILE *out = fopen(output, "w");
unsigned char buf[16];
fprintf(out, "#pragma once \n\n static unsigned char %s[] = { ", globVar);
while(!feof(file))
{
size_t count = fread(buf, 1, 16, file);
for(int n = 0; n < count; ++n)
{
fprintf(out, "0x%02X, ", buf[n]);
}
fprintf(out, "\n");
}
fprintf(out, "};");
fclose(file);
fclose(out);
}
int main()
{
compileBinIntoCharArray("dpad.png", "gDPadPng", "dpad.h");
compileBinIntoCharArray("1.png","gButton1Png", "button1.h");
compileBinIntoCharArray("2.png","gButton2Png", "button2.h");
compileBinIntoCharArray("3.png","gButton3Png", "button3.h");
compileBinIntoCharArray("4.png","gButton4Png", "button4.h");
compileBinIntoCharArray("bckgrnd.png","gButtonBgPng", "buttonBg.h");
compileBinIntoCharArray("confirm.png","gButtonConfirmPng", "buttonConfirm.h");
compileBinIntoCharArray("start.png","gButtonStartPng", "buttonStart.h");
return 0;
}
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