Pārlūkot izejas kodu

Removing PNG support (only TGA and anki textures supported). Android support WIP. Reading from zip is now working (can now pack all assets in one zip)

Panagiotis Christopoulos Charitos 12 gadi atpakaļ
vecāks
revīzija
155e28bdaf

+ 36 - 39
CMakeLists.txt

@@ -1,14 +1,15 @@
 CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
 
-PROJECT(ANKI_PROJ)
+PROJECT(anki)
 
 #
 # Configuration
 #
 
 OPTION(ANKI_BUILD_TOOLS "Build tools" ON)
-OPTION(ANKI_BUILD_TESTS "Build Unit Tests" OFF)
-OPTION(ANKI_BUILD_TESTAPP "Build Test Application" ON)
+OPTION(ANKI_BUILD_TESTS "Build unit tests" OFF)
+OPTION(ANKI_BUILD_TESTAPP "Build test application" ON)
+OPTION(ANKI_BUILD_BENCH "Build benchmark application" OFF)
 
 OPTION(ANKI_WITH_GPERFTOOLS_PROF "Link with gperftools profiler" OFF)
 
@@ -25,38 +26,32 @@ ENDIF()
 SET(ANKI_CPU "X86" CACHE STRING "The CPU arch (X86 or ARM)")
 
 # Address space
-IF(${ANKI_CPU} STREQUAL "ARM")
-	SET(_ADDR_SPACE "32")
-ELSE()
-	SET(_ADDR_SPACE "0")
-ENDIF()
-
-SET(ANKI_CPU_ADDR_SPACE "${_ADDR_SPACE}" CACHE STRING "The CPU architecture (0 or 32 or 64). If zero go native")
+SET(ANKI_CPU_ADDR_SPACE "0" CACHE STRING 
+	"The CPU architecture (0 or 32 or 64). If zero go native")
 
 # SIMD
-OPTION(ANKI_ENABLE_MATH_SIMD "Enable or not math SIMD optimizations" ON)
-IF(ANKI_ENABLE_MATH_SIMD)
-	IF(ANKI_CPU STREQUAL "X86")
-		SET(ANKI_MATH_SIMD "SSE")
-	ELSEIF(ANKI_CPU STREQUAL "ARM")
-		SET(ANKI_MATH_SIMD "NEON")
-	ELSE()
-		MESSAGE(FATAL "Wrong ANKI_CPU set")
-	ENDIF()
+OPTION(ANKI_ENABLE_SIMD "Enable or not SIMD optimizations" ON)
+
+IF(ANKI_ENABLE_SIMD)
+	SET(_ANKI_ENABLE_SIMD 1)
 ELSE()
-	SET(ANKI_MATH_SIMD "NONE")
+	SET(_ANKI_ENABLE_SIMD 0)
 ENDIF()
 
 # Take a wild guess on the windowing system
 IF(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
-	SET(_WIN_BACKEND "GLXX11")
+	IF(${ANDROID})
+		SET(_WIN_BACKEND "ANDROID")
+	ELSE()
+		SET(_WIN_BACKEND "GLXX11")
+	ENDIF()
 ELSEIF(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
 	SET(_WIN_BACKEND "MACOS")
 ELSE()
 	SET(_WIN_BACKEND "DONT_KNOW")
 ENDIF()
 
-SET(ANKI_WINDOW_BACKEND "${_WIN_BACKEND}" CACHE STRING "The window backend (GLXX11 or EGLX11 or EGLFBDEV or MACOS or DUMMY)")
+SET(ANKI_WINDOW_BACKEND "${_WIN_BACKEND}" CACHE STRING "The window backend (GLXX11 or EGLX11 or EGLFBDEV or MACOS or or ANDROID or DUMMY)")
 
 SET(ANKI_GCC_TO_STRING_WORKAROUND "0" CACHE STRING "Enable workaround for C++11 GCC bug (0 or 1)")
 
@@ -71,33 +66,31 @@ OPTION(ANKI_VALGRIND_HAPPY "Make valgrind happy" OFF)
 # Options that affect anki and extern
 #
 
-SET(CXX_FLAGS "")
-SET(C_FLAGS "")
-SET(COMMON_FLAGS "")
+SET(COMPILER_FLAGS "")
 SET(LINKER_FLAGS "")
 
 # address space
 IF(NOT ANKI_CPU_ADDR_SPACE STREQUAL "0")
 	SET(LINKER_FLAGS "${LINKER_FLAGS} -m${ANKI_CPU_ADDR_SPACE} ")
-	SET(COMMON_FLAGS "${COMMON_FLAGS} -m${ANKI_CPU_ADDR_SPACE} ")
+	SET(COMPILER_FLAGS "${COMPILER_FLAGS} -m${ANKI_CPU_ADDR_SPACE} ")
 ENDIF()
 
 # static libstdc++
-SET(CXX_FLAGS "${CXX_FLAGS} -static-libstdc++ ")
+#SET(CXX_FLAGS "${CXX_FLAGS} -static-libstdc++ ")
 
 # SSE
-IF(ANKI_CPU STREQUAL "X86")
-	SET(COMMON_FLAGS "${COMMON_FLAGS} -msse4 ")
+IF(${ANKI_CPU} STREQUAL "X86")
+	SET(COMPILER_FLAGS "${COMPILER_FLAGS} -msse4 ")
 ENDIF()
 
-IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
+IF(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
 	# Debug
 
-	SET(COMMON_FLAGS "${COMMON_FLAGS} -g3 -O0 ")
+	SET(COMPILER_FLAGS "${COMPILER_FLAGS} -g3 -O0 ")
 ELSE()
 	# Release
 
-	SET(COMMON_FLAGS "${COMMON_FLAGS} -ffast-math -O4 -flto ")
+	SET(COMPILER_FLAGS "${COMPILER_FLAGS} -ffast-math -O4 -flto ")
 
 	SET(CXX_FLAGS "${CXX_FLAGS} -fno-rtti ")
 ENDIF()
@@ -113,7 +106,7 @@ ADD_DEFINITIONS(-DGLEW_NO_GLU)
 # Strip
 IF(ANKI_STRIP)
 	SET(LINKER_FLAGS "${LINKER_FLAGS} -s ")
-	SET(COMMON_FLAGS "${COMMON_FLAGS} -s ")
+	SET(COMPILER_FLAGS "${COMPILER_FLAGS} -s ")
 ENDIF()
 
 # gperftools
@@ -128,8 +121,8 @@ INCLUDE_DIRECTORIES(${ANKI_EXTRA_INCLUDE_DIRS})
 LINK_DIRECTORIES(${ANKI_EXTRA_LIB_DIRS})
 
 # Set the flags to cmake now
-SET(CMAKE_CXX_FLAGS "${COMMON_FLAGS} ${CXX_FLAGS}")
-SET(CMAKE_C_FLAGS "${COMMON_FLAGS} ${C_FLAGS}")
+SET(CMAKE_CXX_FLAGS "${CXX_FLAGS} ${COMPILER_FLAGS}")
+SET(CMAKE_C_FLAGS "${C_FLAGS} ${COMPILER_FLAGS}")
 SET(CMAKE_EXE_LINKER_FLAGS "${LINKER_FLAGS}")
 
 #
@@ -160,7 +153,7 @@ ENDIF()
 #
 # Revision
 #
-FIND_PACKAGE(Subversion 1.6 REQUIRED)
+FIND_PACKAGE(Subversion 1.6)
 
 IF(Subversion_FOUND)
 	Subversion_WC_INFO(${CMAKE_CURRENT_SOURCE_DIR} ER)
@@ -176,7 +169,7 @@ SET(ANKI_VERSION_MAJOR 0)
 SET(ANKI_VERSION_MINOR 1)
 MESSAGE("++ AnKi version: ${ANKI_VERSION_MAJOR}.${ANKI_VERSION_MINOR}")
 
-IF(CMAKE_BUILD_TYPE STREQUAL Debug)
+IF(${CMAKE_BUILD_TYPE} STREQUAL Debug)
 	SET(ANKI_DEBUG 1)
 ELSE()
 	SET(ANKI_DEBUG 0)
@@ -190,10 +183,10 @@ INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/anki/Config.h" DESTINATION "${INCLUDE
 #
 INCLUDE_DIRECTORIES("extern/tinyxml2/include" "extern/lua" "extern/png" "extern/z" "extern/bullet" "include" "${CMAKE_CURRENT_BINARY_DIR}")
 
-IF(ANKI_WINDOW_BACKEND STREQUAL "GLXX11" OR ANKI_WINDOW_BACKEND STREQUAL "MACOS")
+IF(${ANKI_WINDOW_BACKEND} STREQUAL "GLXX11" OR ${ANKI_WINDOW_BACKEND} STREQUAL "MACOS")
 	INCLUDE_DIRECTORIES("extern/GLEW/include")
 ELSE()
-	INCLUDE_DIRECTORIES("extern/GLES3/include")
+	#INCLUDE_DIRECTORIES("extern/GLES3/include")
 ENDIF()
 
 #
@@ -224,3 +217,7 @@ IF(ANKI_BUILD_TESTAPP)
 	ADD_SUBDIRECTORY(testapp)
 ENDIF()
 
+IF(ANKI_BUILD_BENCH)
+	ADD_SUBDIRECTORY(bench)
+ENDIF()
+

+ 16 - 4
include/anki/Config.h.cmake

@@ -59,16 +59,28 @@
 #endif
 
 // SIMD
-#define ANKI_MATH_SIMD_NONE 1
-#define ANKI_MATH_SIMD_SSE 2
-#define ANKI_MATH_SIMD_NEON 3
-#define ANKI_MATH_SIMD ANKI_MATH_SIMD_${ANKI_MATH_SIMD}
+#define ANKI_ENABLE_SIMD ${_ANKI_ENABLE_SIMD}
+
+#define ANKI_SIMD_NONE 1
+#define ANKI_SIMD_SSE 2
+#define ANKI_SIMD_NEON 3
+
+#if !ANKI_ENABLE_SIMD
+#	define ANKI_SIMD ANKI_SIMD_NONE
+#else
+#	if ANKI_CPU_ARCH == ANKI_CPU_ARCH_INTEL
+#		define ANKI_SIMD ANKI_SIMD_SSE
+#	elif ANKI_CPU_ARCH == ANKI_CPU_ARCH_ARM
+#		define ANKI_SIMD ANKI_SIMD_NEON
+#	endif
+#endif
 
 // Window backend
 #define ANKI_WINDOW_BACKEND_GLXX11 1
 #define ANKI_WINDOW_BACKEND_EGLX11 2
 #define ANKI_WINDOW_BACKEND_EGLFBDEV 3
 #define ANKI_WINDOW_BACKEND_MACOS 4
+#define ANKI_WINDOW_BACKEND_ANDROID 5
 #define ANKI_WINDOW_BACKEND ANKI_WINDOW_BACKEND_${ANKI_WINDOW_BACKEND}
 #define ANKI_WINDOW_BACKEND_STR "ANKI_WINDOW_BACKEND_${ANKI_WINDOW_BACKEND}"
 

+ 14 - 31
include/anki/core/App.h

@@ -1,17 +1,11 @@
 #ifndef ANKI_CORE_APP_H
 #define ANKI_CORE_APP_H
 
-#include "anki/core/Logger.h"
 #include "anki/util/Singleton.h"
 #include "anki/util/StringList.h"
 
 namespace anki {
 
-class StdinListener;
-class SceneGraph;
-class Camera;
-class Input;
-
 /// The core class of the engine.
 ///
 /// - It initializes the window
@@ -20,26 +14,13 @@ class Input;
 class App
 {
 public:
-	ANKI_HAS_SLOTS(App)
-
 	App()
 	{}
 	~App()
 	{}
 
-	/// This method:
-	/// - Initialize the window
-	/// - Initialize the main renderer
-	/// - Initialize and start the stdin listener
-	/// - Initialize the scripting engine
-	void init(int argc, char* argv[]);
-
-	/// What it does:
-	/// - Destroy the window
-	/// - call exit()
-	void quit(int code);
-
-	static void printAppInfo();
+	/// Initialize the app
+	void init(void* systemSpecificData);
 
 	/// @name Accessors
 	/// @{
@@ -67,6 +48,16 @@ public:
 	}
 	/// @}
 
+	/// What it does:
+	/// - Destroy the window
+	/// - call exit()
+	void quit(int code);
+
+	/// Run the main loop
+	void mainLoop();
+
+	static void printAppInfo();
+
 private:
 	/// The path that holds the configuration
 	std::string settingsPath;
@@ -74,19 +65,11 @@ private:
 	std::string cachePath;
 	F32 timerTick;
 
-	void parseCommandLineArgs(int argc, char* argv[]);
-
-	/// A slot to handle the messageHandler's signal
-	void handleLoggerMessages(const Logger::Info& info);
-	ANKI_SLOT(handleLoggerMessages, const Logger::Info&)
-
-	void initWindow();
-	void initDirs();
-	void initRenderer();
+	void initDirs(void* systemSpecificData);
 };
 
 typedef Singleton<App> AppSingleton;
 
-} // end namespace
+} // end namespace anki
 
 #endif

+ 7 - 0
include/anki/core/NativeWindow.h

@@ -3,6 +3,7 @@
 
 #include "anki/util/StdTypes.h"
 #include "anki/util/Array.h"
+#include "anki/util/Singleton.h"
 #include <string>
 #include <memory>
 
@@ -36,6 +37,9 @@ struct NativeWindowInitializer
 	/// @}
 
 	std::string title = "Untitled window";
+
+	/// System specific data (nedeed in Android)
+	void* systemData = nullptr;
 };
 
 /// Native window with GL context
@@ -86,6 +90,9 @@ private:
 	}
 };
 
+/// Native window singleton
+typedef Singleton<NativeWindow> NativeWindowSingleton;
+
 } // end namespace anki
 
 #endif

+ 31 - 0
include/anki/core/NativeWindowAndroid.h

@@ -0,0 +1,31 @@
+#ifndef ANKI_CORE_NATIVE_WINDOW_ANDROID_H
+#define ANKI_CORE_NATIVE_WINDOW_ANDROID_H
+
+#include "anki/core/NativeWindow.h"
+#include <EGL/egl.h>
+#include <GLES3/gl3.h>
+#include <android_native_app_glue.h>
+
+namespace anki {
+
+/// Native window implementation for Android
+struct NativeWindowImpl
+{
+	EGLDisplay display = EGL_NO_DISPLAY;
+	EGLSurface surface = EGL_NO_SURFACE;
+	EGLContext context = EGL_NO_CONTEXT;
+	android_app* andApp = nullptr;
+
+	~NativeWindowImpl()
+	{
+		destroy();
+	}
+
+	void create(NativeWindowInitializer& init);
+	void destroy();
+};
+
+} // end namespace anki
+
+#endif
+

+ 10 - 2
include/anki/input/Input.h

@@ -55,11 +55,17 @@ public:
 	/// Move the mouse cursor to a position inside the window. Useful for 
 	/// locking the cursor into a fixed location (eg in the center of the 
 	/// screen)
-	void moveMouse(const Vec2& posNdc);
+	void moveCursor(const Vec2& posNdc);
 
 	/// Hide the mouse cursor
 	void hideCursor(Bool hide);
 
+	/// Lock mouse to (0, 0)
+	void lockCursor(Bool lock)
+	{
+		lockCurs = lock;
+	}
+
 private:
 	NativeWindow* nativeWindow = nullptr;
 
@@ -76,9 +82,11 @@ private:
 	Array<U32, 8> mouseBtns;
 	/// @}
 
-	Vec2 mousePosNdc; ///< The coords are in the NDC space
+	Vec2 mousePosNdc = Vec2(2.0); ///< The coords are in the NDC space
 
 	std::shared_ptr<InputImpl> impl;
+
+	Bool8 lockCurs = false;
 };
 
 typedef Singleton<Input> InputSingleton;

+ 2 - 2
include/anki/math/Mat4.h

@@ -15,7 +15,7 @@ struct TMat4Simd
 	typedef Array<T, 16> Type;
 };
 
-#if ANKI_MATH_SIMD == ANKI_MATH_SIMD_SSE
+#if ANKI_SIMD == ANKI_SIMD_SSE
 // Specialize for F32
 template<>
 struct TMat4Simd<F32>
@@ -791,7 +791,7 @@ private:
 	/// @}
 };
 
-#if ANKI_MATH_SIMD == ANKI_MATH_SIMD_SSE
+#if ANKI_SIMD == ANKI_SIMD_SSE
 
 // Forward declare specializations
 

+ 1 - 1
include/anki/math/Mat4.inl.h

@@ -44,7 +44,7 @@ TMat4<T> operator/(const T f, const TMat4<T>& m4)
 	return out;
 }
 
-#if ANKI_MATH_SIMD == ANKI_MATH_SIMD_SSE
+#if ANKI_SIMD == ANKI_SIMD_SSE
 
 //==============================================================================
 // SSE specializations                                                         =

+ 3 - 3
include/anki/math/Simd.h

@@ -3,11 +3,11 @@
 
 #include "anki/Config.h"
 
-#if ANKI_MATH_SIMD == ANKI_MATH_SIMD_SSE
+#if ANKI_SIMD == ANKI_SIMD_SSE
 #	include <smmintrin.h>
-#elif ANKI_MATH_SIMD == ANKI_MATH_SIMD_NEON
+#elif ANKI_SIMD == ANKI_SIMD_NEON
 #	include <arm_neon.h>
-#elif ANKI_MATH_SIMD == ANKI_MATH_SIMD_NONE
+#elif ANKI_SIMD == ANKI_SIMD_NONE
 #	define ANKI_DUMMY_DUMMY_DUMMY 1
 #else
 #	error "See file"

+ 4 - 4
include/anki/math/Vec4.h

@@ -15,14 +15,14 @@ struct TVec4Simd
 	typedef Array<T, 4> Type;
 };
 
-#if ANKI_MATH_SIMD == ANKI_MATH_SIMD_SSE
+#if ANKI_SIMD == ANKI_SIMD_SSE
 // Specialize for F32
 template<>
 struct TVec4Simd<F32>
 {
 	typedef __m128 Type;
 };
-#elif ANKI_MATH_SIMD == ANKI_MATH_SIMD_NEON
+#elif ANKI_SIMD == ANKI_SIMD_NEON
 // Specialize for F32
 template<>
 struct TVec4Simd<F32>
@@ -403,7 +403,7 @@ private:
 	/// @}
 };
 
-#if ANKI_MATH_SIMD == ANKI_MATH_SIMD_SSE
+#if ANKI_SIMD == ANKI_SIMD_SSE
 
 // Forward declare specializations
 
@@ -455,7 +455,7 @@ TVec4<F32> TVec4<F32>::getNormalized() const;
 template<>
 void TVec4<F32>::normalize();
 
-#elif ANKI_MATH_SIMD == ANKI_MATH_SIMD_NEON
+#elif ANKI_SIMD == ANKI_SIMD_NEON
 
 template<>
 TVec4<F32>::TVec4(F32 f);

+ 2 - 2
include/anki/math/Vec4.inl.h

@@ -34,7 +34,7 @@ TVec4<T> operator/(const T f, const TVec4<T>& v4)
 	return TVec4<T>(f) / v4;
 }
 
-#if ANKI_MATH_SIMD == ANKI_MATH_SIMD_SSE
+#if ANKI_SIMD == ANKI_SIMD_SSE
 
 //==============================================================================
 // SSE specializations                                                         =
@@ -173,7 +173,7 @@ inline void TVec4<F32>::normalize()
 	simd = _mm_mul_ps(simd, inverseNorm);
 }
 
-#elif ANKI_MATH_SIMD == ANKI_MATH_SIMD_NEON
+#elif ANKI_SIMD == ANKI_SIMD_NEON
 
 //==============================================================================
 // NEON specializations                                                        =

+ 1 - 1
include/anki/resource/ResourceManager.h

@@ -47,7 +47,7 @@ private:
 /// The singleton of resource manager
 typedef Singleton<ResourceManager> ResourceManagerSingleton;
 
-/// XXX
+/// Convenience macro to sanitize resources
 #define ANKI_R(x_) \
 	ResourceManagerSingleton::get().fixResourcePath(x_).c_str()
 

+ 3 - 4
include/anki/resource/ResourceManager.inl.h

@@ -12,6 +12,8 @@ void TypeResourceManager<Type>::
 	newInstance = nullptr;
 	std::string newFname;
 
+	newFname = ResourceManagerSingleton::get().fixResourcePath(filename);
+
 	// Alloc
 	try
 	{
@@ -19,15 +21,12 @@ void TypeResourceManager<Type>::
 	}
 	catch(const std::exception& e)
 	{
-		throw ANKI_EXCEPTION("Constructor failed for: " + filename) << e;
+		throw ANKI_EXCEPTION("Constructor failed for: " + newFname) << e;
 	}
 
 	// Load
 	try
 	{
-		newFname = 
-			ResourceManagerSingleton::get().fixResourcePath(filename);
-
 		newInstance->load(newFname.c_str());
 	}
 	catch(std::exception& e)

+ 32 - 12
include/anki/util/File.h

@@ -4,6 +4,11 @@
 #include "anki/util/StringList.h"
 #include <string>
 
+// Forward
+#if ANKI_OS == ANKI_OS_ANDROID
+struct AAssetManager;
+#endif
+
 namespace anki {
 
 /// @addtogroup util
@@ -19,24 +24,25 @@ private:
 	enum FileType
 	{
 		FT_C = 1 << 0, ///< C file
-		FT_ZIP = 1 << 1 ///< Ziped file
+		FT_ZIP = 1 << 1, ///< Ziped file
+		FT_SPECIAL = 1 << 2 ///< For example file located in the android apk 
 	};
 
 public:
 	/// Open mode
 	enum OpenFlag
 	{
-		OF_READ = 1 << 2,
-		OF_WRITE = 1 << 3,
-		OF_APPEND = OF_WRITE | (1 << 4),
-		OF_BINARY = 1 << 5
+		OF_READ = 1 << 3,
+		OF_WRITE = 1 << 4,
+		OF_APPEND = OF_WRITE | (1 << 5),
+		OF_BINARY = 1 << 6
 	};
 
 	/// The 2 available byte orders. Used in binary files.
 	enum Endianness
 	{
-		E_LITTLE_ENDIAN = 1 << 6, ///< The default
-		E_BIG_ENDIAN = 1 << 7
+		E_LITTLE_ENDIAN = 1 << 7, ///< The default
+		E_BIG_ENDIAN = 1 << 8
 	};
 
 	/// Passed to seek function
@@ -53,7 +59,7 @@ public:
 	{}
 
 	/// Open file
-	File(const char* filename, U8 openMask)
+	File(const char* filename, U16 openMask)
 		: file(nullptr), flags(0)
 	{
 		open(filename, openMask);
@@ -66,7 +72,7 @@ public:
 	/// @param[in] filename The file to open
 	/// @param[in] openMask The open flags. It's a combination of OpenFlag and 
 	///                     Endianness enums
-	void open(const char* filename, U8 openMask);
+	void open(const char* filename, U16 openMask);
 
 	/// Close the file
 	void close();
@@ -117,22 +123,36 @@ public:
 
 	/// File exists?
 	static Bool fileExists(const char* filename);
+
+#if ANKI_OS == ANKI_OS_ANDROID
+	static void setAndroidAssetManager(AAssetManager* manager)
+	{
+		andAssetManager = manager;
+	}
+#endif
 	/// @}
 
 private:
 	void* file; ///< A native type
-	U8 flags; ///< All the flags. Initialy zero and set on open
+	U16 flags; ///< All the flags. Initialy zero and set on open
 
 	/// Get the current machine's endianness
 	static Endianness getMachineEndianness();
 
 	/// Open a C file
-	void openCFile(const char* filename, U8 flags);
+	void openCFile(const char* filename, U16 flags);
 
 	/// Open an archive and the file inside
 	/// @param[in] archive The filename of the archive
 	/// @param[in] archived The filename of the file inside the archive
-	void openZipFile(const char* archive, const char* archived, U8 flags);
+	void openZipFile(const char* archive, const char* archived, U16 flags);
+
+#if ANKI_OS == ANKI_OS_ANDROID
+	static AAssetManager* andAssetManager;
+
+	/// Open an Android file
+	void openAndFile(const char* filename, U16 flags);
+#endif
 };
 
 /// Directory exists?

+ 1 - 1
pack_data.sh

@@ -1,5 +1,5 @@
 #!/bin/sh
 rm data.ankizip
 cd data
-zip -r ../data.ankizip . -i '*.mtl' '*.mdl' '*.mesh' '*.scene' '*.ankitex' '*.tga' '*.png' '*.ttf' '*.ogg'
+zip -r ../data.ankizip . -i '*.mtl' '*.mdl' '*.mesh' '*.scene' '*.ankitex' '*.tga' '*.ttf' '*.ogg' '*.glsl' '*.ankipart'
 cd -

+ 11 - 7
src/CMakeLists.txt

@@ -10,19 +10,23 @@ FOREACH(TMP ${ANKI_SUB_DIRS})
 	SET(ANKI_LIBS ${ANKI_LIBS} anki${TMP})
 ENDFOREACH()
 
-ADD_LIBRARY(anki Dummy.cpp)
-
-# Set the platform GL libraries
+# Set the platform libraries
 IF(ANKI_WINDOW_BACKEND STREQUAL "GLXX11")
-	SET(_GL GL ankiglew)
+	SET(_SYS GL ankiglew)
 ELSEIF(ANKI_WINDOW_BACKEND STREQUAL "MACOS")
 	FIND_PACKAGE(OpenGL REQUIRED)
-	SET(_GL ${OPENGL_LIBRARIES} ankiglew)
+	SET(_SYS ${OPENGL_LIBRARIES} ankiglew)
+ELSEIF(ANKI_WINDOW_BACKEND STREQUAL "ANDROID")
+	SET(_SYS GLESv2 EGL log android)
+	INCLUDE_DIRECTORIES("${ANDROID_NDK}/sources/android/native_app_glue")
+	SET(_SYS_SRC "${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c")
 ELSE()
-	SET(_GL GLESv2 EGL mali)
+	SET(_SYS GLESv2 EGL mali)
 ENDIF()
 
-TARGET_LINK_LIBRARIES(anki ${ANKI_LIBS} ankitinyxml2 ankilua ankibullet ankiz ankipng ${ANKI_GPERFTOOLS_LIBS} pthread ${_GL})
+ADD_LIBRARY(anki Dummy.cpp "${_SYS_SRC}")
+
+TARGET_LINK_LIBRARIES(anki ${ANKI_LIBS} ankitinyxml2 ankilua ankibullet ankiz ankipng ${ANKI_GPERFTOOLS_LIBS} pthread ${_SYS})
 
 SET_TARGET_PROPERTIES(anki PROPERTIES LINKER_LANGUAGE CXX)
 

+ 81 - 61
src/core/App.cpp

@@ -1,9 +1,14 @@
 #include "anki/core/App.h"
+#include "anki/Config.h"
 #include "anki/core/Logger.h"
 #include "anki/util/Exception.h"
 #include "anki/util/File.h"
 #include "anki/util/System.h"
-#include "anki/Config.h"
+#include "anki/scene/SceneGraph.h"
+#include "anki/renderer/MainRenderer.h"
+#include "anki/input/Input.h"
+#include "anki/core/NativeWindow.h"
+#include "anki/core/Counters.h"
 #include <cstring>
 #include <sstream>
 #include <iostream>
@@ -14,7 +19,7 @@
 namespace anki {
 
 //==============================================================================
-/// Segfault signal handler
+/// Bad things signal handler
 static void handler(int sig)
 {
 	void *array[10];
@@ -30,78 +35,23 @@ static void handler(int sig)
 }
 
 //==============================================================================
-void App::handleLoggerMessages(const Logger::Info& info)
-{
-	std::ostream* out = NULL;
-	const char* x = NULL;
-	const char* terminalColor = nullptr;
-
-	switch(info.type)
-	{
-	case Logger::LMT_NORMAL:
-		out = &std::cout;
-		x = "Info";
-		terminalColor = "\033[0;32m";
-		break;
-	case Logger::LMT_ERROR:
-		out = &std::cerr;
-		x = "Error";
-		terminalColor = "\033[0;31m";
-		break;
-	case Logger::LMT_WARNING:
-		out = &std::cerr;
-		x = "Warn";
-		terminalColor = "\033[0;33m";
-		break;
-	}
-
-	(*out) << terminalColor << "(" << info.file << ":" << info.line << " "
-		<< info.func << ") " << x << ": " << info.msg << "\033[0m" << std::endl;
-}
-
-//==============================================================================
-void App::parseCommandLineArgs(int argc, char* argv[])
-{
-#if 0
-	for(int i = 1; i < argc; i++)
-	{
-		char* arg = argv[i];
-		if(strcmp(arg, "--terminal-coloring") == 0)
-		{
-			terminalColoringEnabled = true;
-		}
-		else if(strcmp(arg, "--no-terminal-coloring") == 0)
-		{
-			terminalColoringEnabled = false;
-		}
-		else
-		{
-			std::cerr << "Incorrect command line argument: " << arg
-				<< std::endl;
-			abort();
-		}
-	}
-#endif
-}
-
-//==============================================================================
-void App::init(int argc, char* argv[])
+void App::init(void* systemSpecificData)
 {
 	// Install signal handlers
 	signal(SIGSEGV, handler);
 	signal(SIGBUS, handler);
 	signal(SIGFPE, handler);
 
-	parseCommandLineArgs(argc, argv);
 	printAppInfo();
-	initDirs();
+	initDirs(systemSpecificData);
 
 	timerTick = 1.0 / 60.0; // in sec. 1.0 / period
 }
 
 //==============================================================================
-void App::initDirs()
+void App::initDirs(void* systemSpecificData)
 {
+#if ANKI_OS != ANKI_OS_ANDROID
 	// Settings path
 	settingsPath = std::string(getenv("HOME")) + "/.anki";
 	if(!directoryExists(settingsPath.c_str()))
@@ -120,6 +70,29 @@ void App::initDirs()
 
 	ANKI_LOGI("Creating cache dir: %s", cachePath.c_str());
 	createDirectory(cachePath.c_str());
+#else
+	ANKI_ASSERT(systemSpecificData);
+	ANativeActivity* activity = (ANativeActivity*)systemSpecificData;
+
+	// Settings path
+	settingsPath = std::string(activity->internalDataPath);
+	if(!directoryExists(settingsPath.c_str()))
+	{
+		ANKI_LOGI("Creating settings dir: %s", settingsPath.c_str());
+		createDirectory(settingsPath.c_str());
+	}
+
+	// Cache
+	cachePath = settingsPath + "/cache";
+	if(directoryExists(cachePath.c_str()))
+	{
+		ANKI_LOGI("Deleting dir: %s", cachePath.c_str());
+		removeDirectory(cachePath.c_str());
+	}
+
+	ANKI_LOGI("Creating cache dir: %s", cachePath.c_str());
+	createDirectory(cachePath.c_str());
+#endif
 }
 
 //==============================================================================
@@ -149,4 +122,51 @@ void App::printAppInfo()
 	ANKI_LOGI(msg.str().c_str());
 }
 
+//==============================================================================
+void App::mainLoop()
+{
+	ANKI_LOGI("Entering main loop");
+
+	HighRezTimer::Scalar prevUpdateTime = HighRezTimer::getCurrentTime();
+	HighRezTimer::Scalar crntTime = prevUpdateTime;
+
+	SceneGraph& scene = SceneGraphSingleton::get();
+	MainRenderer& renderer = MainRendererSingleton::get();
+	Input& input = InputSingleton::get();
+	NativeWindow& window = NativeWindowSingleton::get();
+
+	ANKI_COUNTER_START_TIMER(C_FPS);
+	while(true)
+	{
+		HighRezTimer timer;
+		timer.start();
+
+		prevUpdateTime = crntTime;
+		crntTime = HighRezTimer::getCurrentTime();
+
+		// Update
+		input.handleEvents();
+		scene.update(
+			prevUpdateTime, crntTime, MainRendererSingleton::get());
+		renderer.render(SceneGraphSingleton::get());
+
+		window.swapBuffers();
+		ANKI_COUNTERS_RESOLVE_FRAME();
+
+		// Sleep
+		timer.stop();
+		if(timer.getElapsedTime() < getTimerTick())
+		{
+			HighRezTimer::sleep(getTimerTick() - timer.getElapsedTime());
+		}
+
+		// Timestamp
+		increaseGlobTimestamp();
+	}
+
+	// Counters end
+	ANKI_COUNTER_STOP_TIMER_INC(C_FPS);
+	ANKI_COUNTERS_FLUSH();
+}
+
 } // end namespace anki

+ 8 - 6
src/core/CMakeLists.txt

@@ -1,17 +1,19 @@
 SET(ANKI_CORE_SOURCES App.cpp Async.cpp Logger.cpp StdinListener.cpp ThreadPool.cpp Timestamp.cpp Counters.cpp)
 
-IF(ANKI_WINDOW_BACKEND STREQUAL "GLXX11")
+IF(${ANKI_WINDOW_BACKEND} STREQUAL "GLXX11")
 	SET(ANKI_CORE_SOURCES ${ANKI_CORE_SOURCES} NativeWindowGlxX11.cpp)
-ELSEIF(ANKI_WINDOW_BACKEND STREQUAL "EGLX11")
+ELSEIF(${ANKI_WINDOW_BACKEND} STREQUAL "EGLX11")
 	SET(ANKI_CORE_SOURCES ${ANKI_CORE_SOURCES} NativeWindowEglX11.cpp)
-ELSEIF(ANKI_WINDOW_BACKEND STREQUAL "EGLFBDEV")
+ELSEIF(${ANKI_WINDOW_BACKEND} STREQUAL "EGLFBDEV")
 	SET(ANKI_CORE_SOURCES ${ANKI_CORE_SOURCES} NativeWindowEglFbdev.cpp)
-ELSEIF(ANKI_WINDOW_BACKEND STREQUAL "MACOS")
+ELSEIF(${ANKI_WINDOW_BACKEND} STREQUAL "MACOS")
 	SET(ANKI_CORE_SOURCES ${ANKI_CORE_SOURCES} NativeWindowMacos.cpp)
-ELSEIF(ANKI_WINDOW_BACKEND STREQUAL "DUMMY")
+ELSEIF(${ANKI_WINDOW_BACKEND} STREQUAL "ANDROID")
+	SET(ANKI_CORE_SOURCES ${ANKI_CORE_SOURCES} NativeWindowAndroid.cpp)
+ELSEIF(${ANKI_WINDOW_BACKEND} STREQUAL "DUMMY")
 	SET(ANKI_CORE_SOURCES ${ANKI_CORE_SOURCES} NativeWindowDummy.cpp)
 ELSE()
-	MESSAGE(FATAL "Unrecognized ANKI_WINDOW_BACKEND: ${ANKI_WINDOW_BACKEND}")
+	MESSAGE(FATAL_ERROR "Unrecognized ANKI_WINDOW_BACKEND: ${ANKI_WINDOW_BACKEND}")
 ENDIF()
 
 ADD_LIBRARY(ankicore ${ANKI_CORE_SOURCES})

+ 1 - 1
src/core/Logger.cpp

@@ -29,7 +29,7 @@ void Logger::write(const char* file, int line, const char* func,
 void Logger::writeFormated(const char* file, int line, const char* func,
 	LoggerMessageType type, const char* fmt, ...)
 {
-	char buffer[1024];
+	char buffer[1024 * 10];
 	va_list args;
 
 	va_start(args, fmt);

+ 176 - 0
src/core/NativeWindowAndroid.cpp

@@ -0,0 +1,176 @@
+#include "anki/core/NativeWindowAndroid.h"
+#include "anki/util/Exception.h"
+#include "anki/util/Array.h"
+#include "anki/util/StdTypes.h"
+
+namespace anki {
+
+//==============================================================================
+// NativeWindowImpl                                                            =
+//==============================================================================
+
+//==============================================================================
+void NativeWindowImpl::create(NativeWindowInitializer& init)
+{
+	Array<EGLint, 256> attribs;
+	U attr = 0;
+	EGLint configsCount;
+	EGLint format;
+
+	ANKI_ASSERT(init.systemData != nullptr);
+	andApp = (android_app*)init.systemData;
+
+	// EGL init
+	//
+	display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+	if(display == EGL_NO_DISPLAY)
+	{
+		throw ANKI_EXCEPTION("Failed to create display");
+	}
+
+	int major, minor;
+	if(eglInitialize(display, &major, &minor) == EGL_FALSE)
+	{
+		throw ANKI_EXCEPTION("Failed to initialize EGL");
+	}
+
+	// 
+	// EGL config
+	//  
+	attribs[attr++] = EGL_SURFACE_TYPE;
+	attribs[attr++] = EGL_WINDOW_BIT,
+
+	attribs[attr++] = EGL_RENDERABLE_TYPE;
+	attribs[attr++] = EGL_OPENGL_ES2_BIT;
+
+	if(init.samplesCount > 1)
+	{
+		attribs[attr++] = EGL_SAMPLES;
+		attribs[attr++] = init.samplesCount;
+	}
+
+	attribs[attr++] = EGL_RED_SIZE;
+	attribs[attr++] = init.rgbaBits[0];
+	attribs[attr++] = EGL_GREEN_SIZE;
+	attribs[attr++] = init.rgbaBits[1];
+	attribs[attr++] = EGL_BLUE_SIZE;
+	attribs[attr++] = init.rgbaBits[2];
+	attribs[attr++] = EGL_ALPHA_SIZE;
+	attribs[attr++] = init.rgbaBits[3];
+
+	attribs[attr++] = EGL_DEPTH_SIZE;
+	attribs[attr++] = init.depthBits;
+	attribs[attr++] = EGL_STENCIL_SIZE;
+	attribs[attr++] = init.stencilBits;
+
+	attribs[attr++] = EGL_NONE;
+
+	if(eglChooseConfig(
+		display, &attribs[0], &config, 1, &configsCount) == EGL_FALSE)
+	{
+		throw ANKI_EXCEPTION("Failed to query required EGL configs");
+	}
+
+	if(configsCount == 0)
+	{
+		throw ANKI_EXCEPTION("No matching EGL configs found");
+	}
+
+	eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
+
+	ANKI_ASSERT(andApp->window);
+	ANativeWindow_setBuffersGeometry(andApp->window, 0, 0, format);
+
+	// Surface
+	//
+	surface = eglCreateWindowSurface(display, config, andApp->window, NULL);
+	if(surface == EGL_NO_SURFACE)
+	{
+		throw ANKI_EXCEPTION("Cannot create surface");
+	}
+
+	// Context
+	//
+	EGLint ctxAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
+
+	context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctxAttribs);
+	if(context == EGL_NO_CONTEXT)
+	{
+		throw ANKI_EXCEPTION("Cannot create context");
+	}
+
+	if(eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
+	{
+		throw ANKI_EXCEPTION("Cannot make the context current");
+	}
+
+	// Query width and height
+	//
+	EGLint w, h;
+	eglQuerySurface(display, surface, EGL_WIDTH, &w);
+	eglQuerySurface(display, surface, EGL_HEIGHT, &h);
+
+	init.width = w;
+	init.height = h;
+}
+
+//==============================================================================
+void NativeWindowImpl::destroy()
+{
+	if(display != EGL_NO_DISPLAY) 
+	{
+		eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+		if(context != EGL_NO_CONTEXT) 
+		{
+			eglDestroyContext(display, context);
+		}
+
+		if(engine->surface != EGL_NO_SURFACE) 
+		{
+			eglDestroySurface(display, surface);
+		}
+
+		eglTerminate(display);
+	}
+}
+
+
+//==============================================================================
+// NativeWindow                                                                =
+//==============================================================================
+
+//==============================================================================
+NativeWindow::~NativeWindow()
+{}
+
+//==============================================================================
+void NativeWindow::create(NativeWindowInitializer& initializer)
+{
+	impl.reset(new NativeWindowImpl);
+	impl->create(initializer);
+
+	// Set the size after because the create may have changed it to something
+	// more nice
+	width = initializer.width;
+	height = initializer.height;
+}
+
+//==============================================================================
+void NativeWindow::destroy()
+{
+	impl.reset();
+}
+
+//==============================================================================
+void NativeWindow::swapBuffers()
+{
+	ANKI_ASSERT(isCreated());
+	if(eglSwapBuffers(impl->display, impl->surface) == EGL_FALSE)
+	{
+		throw ANKI_EXCEPTION("eglSwapBuffers() failed");
+	}
+}
+
+} // end namespace anki
+

+ 2 - 2
src/gl/BufferObject.cpp

@@ -40,8 +40,8 @@ void BufferObject::destroy()
 	{
 		unbind();
 		glDeleteBuffers(objectsCount, &glIds[0]);
-		memset(&glIds[0], sizeof(Base::glIds), 0);
-		objectsCount = 0;
+		memset(&glIds[0], 0, sizeof(Base::glIds));
+		objectsCount = 1;
 	}
 }
 

+ 1 - 1
src/input/InputDummy.cpp

@@ -15,7 +15,7 @@ void Input::init(NativeWindow* nativeWindow)
 }
 
 //==============================================================================
-void Input::moveMouse(const Vec2& posNdc)
+void Input::moveCursor(const Vec2& posNdc)
 {
 	// You are dummy... do nothing
 }

+ 1 - 1
src/input/InputMacos.cpp

@@ -20,7 +20,7 @@ void Input::handleEvents()
 }
 
 //==============================================================================
-void Input::moveMouse(const Vec2& pos)
+void Input::moveCursor(const Vec2& pos)
 {
 	// XXX Add platform code
 }

+ 7 - 1
src/input/InputX11.cpp

@@ -269,10 +269,16 @@ skipXNextEvent:
 			break;
 		}
 	}
+
+	// Lock mouse
+	if(lockCurs)
+	{
+		moveCursor(Vec2(0.0));
+	}
 }
 
 //==============================================================================
-void Input::moveMouse(const Vec2& pos)
+void Input::moveCursor(const Vec2& pos)
 {
 	DBG_LOGI("Moving to: " << pos.x() << " " << pos.y());
 

+ 3 - 275
src/resource/Image.cpp

@@ -5,8 +5,6 @@
 #include "anki/util/Assert.h"
 #include "anki/util/Array.h"
 #include "anki/misc/Xml.h"
-#include <png.h>
-#include <fstream>
 
 namespace anki {
 
@@ -20,15 +18,11 @@ static U8 tgaHeaderCompressed[12] = {0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
 //==============================================================================
 static void loadUncompressedTga(
-	std::fstream& fs, U32& width, U32& height, U32& bpp, Vector<U8>& data)
+	File& fs, U32& width, U32& height, U32& bpp, Vector<U8>& data)
 {
 	// read the info from header
 	U8 header6[6];
 	fs.read((char*)&header6[0], sizeof(header6));
-	if(fs.gcount() != sizeof(header6))
-	{
-		throw ANKI_EXCEPTION("Cannot read info header");
-	}
 
 	width  = header6[1] * 256 + header6[0];
 	height = header6[3] * 256 + header6[2];
@@ -45,10 +39,6 @@ static void loadUncompressedTga(
 	data.resize(imageSize);
 
 	fs.read(reinterpret_cast<char*>(&data[0]), imageSize);
-	if(fs.gcount() != imageSize)
-	{
-		throw ANKI_EXCEPTION("Cannot read image data");
-	}
 
 	// swap red with blue
 	for(int i = 0; i < int(imageSize); i += bytesPerPxl)
@@ -61,14 +51,10 @@ static void loadUncompressedTga(
 
 //==============================================================================
 static void loadCompressedTga(
-	std::fstream& fs, U32& width, U32& height, U32& bpp, Vector<U8>& data)
+	File& fs, U32& width, U32& height, U32& bpp, Vector<U8>& data)
 {
 	U8 header6[6];
 	fs.read((char*)&header6[0], sizeof(header6));
-	if(fs.gcount() != sizeof(header6))
-	{
-		throw ANKI_EXCEPTION("Cannot read info header");
-	}
 
 	width  = header6[1] * 256 + header6[0];
 	height = header6[3] * 256 + header6[2];
@@ -93,10 +79,6 @@ static void loadCompressedTga(
 		U8 chunkheader = 0;
 
 		fs.read((char*)&chunkheader, sizeof(U8));
-		if(fs.gcount() != sizeof(U8))
-		{
-			throw ANKI_EXCEPTION("Cannot read RLE header");
-		}
 
 		if(chunkheader < 128)
 		{
@@ -104,10 +86,6 @@ static void loadCompressedTga(
 			for(int counter = 0; counter < chunkheader; counter++)
 			{
 				fs.read((char*)&colorbuffer[0], bytesPerPxl);
-				if(fs.gcount() != bytesPerPxl)
-				{
-					throw ANKI_EXCEPTION("Cannot read image data");
-				}
 
 				data[currentbyte] = colorbuffer[2];
 				data[currentbyte + 1] = colorbuffer[1];
@@ -131,10 +109,6 @@ static void loadCompressedTga(
 		{
 			chunkheader -= 127;
 			fs.read((char*)&colorbuffer[0], bytesPerPxl);
-			if(fs.gcount() != bytesPerPxl)
-			{
-				throw ANKI_EXCEPTION("Cannot read from file");
-			}
 
 			for(int counter = 0; counter < chunkheader; counter++)
 			{
@@ -163,21 +137,10 @@ static void loadCompressedTga(
 static void loadTga(const char* filename, 
 	U32& width, U32& height, U32& bpp, Vector<U8>& data)
 {
-	std::fstream fs;
+	File fs(filename, File::OF_READ | File::OF_BINARY);
 	char myTgaHeader[12];
-	fs.open(filename, std::ios::in | std::ios::binary);
-
-	if(!fs.is_open())
-	{
-		throw ANKI_EXCEPTION("Cannot open file");
-	}
 
 	fs.read(&myTgaHeader[0], sizeof(myTgaHeader));
-	if(fs.gcount() != sizeof(myTgaHeader))
-	{
-		fs.close();
-		throw ANKI_EXCEPTION("Cannot read file header");
-	}
 
 	if(memcmp(tgaHeaderUncompressed, &myTgaHeader[0], sizeof(myTgaHeader)) == 0)
 	{
@@ -197,216 +160,6 @@ static void loadTga(const char* filename,
 	{
 		throw ANKI_EXCEPTION("Invalid bpp");
 	}
-
-	fs.close();
-}
-
-//==============================================================================
-// PNG                                                                         =
-//==============================================================================
-
-//==============================================================================
-static Bool loadPng(const char* filename, std::string& err, 
-	U32& bpp, U32& width, U32& height, Vector<U8>& data) throw()
-{
-	// All locals
-	//
-	const U32 PNG_SIG_SIZE = 8; // PNG header size
-	FILE* file = NULL;
-	png_structp pngPtr = NULL;
-	png_infop infoPtr = NULL;
-	Bool ok = false;
-	PtrSize charsRead;
-	U32 bitDepth;
-	//U32 channels;
-	U32 rowbytes;
-	U32 colorFormat;
-	Vector<png_bytep> rowPointers;
-
-	// Open file
-	//
-	file = fopen(filename, "rb");
-	if(file == NULL)
-	{
-		err = "Cannot open file";
-		goto cleanup;
-	}
-
-	// Validate PNG header
-	//
-	png_byte pngsig[PNG_SIG_SIZE];
-	charsRead = fread(pngsig, 1, PNG_SIG_SIZE, file);
-	if(charsRead != PNG_SIG_SIZE)
-	{
-		err = "Cannot read PNG header";
-		goto cleanup;
-	}
-
-	if(png_sig_cmp(pngsig, 0, PNG_SIG_SIZE) != 0)
-	{
-		err = "File not PNG image";
-		goto cleanup;
-	}
-
-	// Crete some PNG structs
-	//
-	pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-	if(!pngPtr)
-	{
-		throw ANKI_EXCEPTION("png_create_read_struct failed");
-		goto cleanup;
-	}
-
-	infoPtr = png_create_info_struct(pngPtr);
-	if(!infoPtr)
-	{
-		err = "png_create_info_struct failed";
-		goto cleanup;
-	}
-
-	// Set error handling
-	//
-	if(setjmp(png_jmpbuf(pngPtr)))
-	{
-		err = "Reading PNG file failed";
-		goto cleanup;
-	}
-
-	// Init io
-	//
-	png_init_io(pngPtr, file);
-	// PNG lib knows that we already have read the header
-	png_set_sig_bytes(pngPtr, PNG_SIG_SIZE);
-
-	// Read info and make conversions
-	// This loop reads info, if not acceptable it calls libpng funcs to change
-	// them and re-runs the loop
-	//
-	png_read_info(pngPtr, infoPtr);
-	while(true)
-	{
-		width = png_get_image_width(pngPtr, infoPtr);
-		height = png_get_image_height(pngPtr, infoPtr);
-		bitDepth = png_get_bit_depth(pngPtr, infoPtr);
-		//channels = png_get_channels(pngPtr, infoPtr);
-		colorFormat = png_get_color_type(pngPtr, infoPtr);
-
-		// 1) Convert the color types
-		switch(colorFormat)
-		{
-		case PNG_COLOR_TYPE_PALETTE:
-			err = "Converting PNG_COLOR_TYPE_PALETTE to "
-				"PNG_COLOR_TYPE_RGB or PNG_COLOR_TYPE_RGBA";
-			png_set_palette_to_rgb(pngPtr);
-			goto again;
-			break;
-		case PNG_COLOR_TYPE_GRAY:
-			// do nothing
-			break;
-		case PNG_COLOR_TYPE_GRAY_ALPHA:
-			err = "Cannot accept PNG_COLOR_TYPE_GRAY_ALPHA. "
-				"Converting to PNG_COLOR_TYPE_GRAY";
-			png_set_strip_alpha(pngPtr);
-			goto again;
-			break;
-		case PNG_COLOR_TYPE_RGB:
-			// do nothing
-			break;
-		case PNG_COLOR_TYPE_RGBA:
-			// do nothing
-			break;
-		default:
-			throw ANKI_EXCEPTION("Forgot to handle a color type");
-			break;
-		}
-
-		// 2) Convert the bit depths
-		if(colorFormat == PNG_COLOR_TYPE_GRAY && bitDepth < 8)
-		{
-			err = "Converting bit depth";
-#if 0
-			png_set_gray_1_2_4_to_8(pngPtr);
-#endif
-			goto again;
-		}
-
-		if(bitDepth > 8)
-		{
-			err = "Converting bit depth";
-			png_set_strip_16(pngPtr);
-		}
-
-		break;
-
-		again:
-			png_read_update_info(pngPtr, infoPtr);
-	}
-
-	// Sanity checks
-	if((bitDepth != 8)
-		|| (colorFormat != PNG_COLOR_TYPE_GRAY
-			&& colorFormat != PNG_COLOR_TYPE_RGB
-			&& colorFormat != PNG_COLOR_TYPE_RGBA))
-	{
-		err = "Sanity checks failed";
-		goto cleanup;
-	}
-
-	// Read this sucker
-	//
-	rowbytes = png_get_rowbytes(pngPtr, infoPtr);
-
-	rowPointers.resize(height * sizeof(png_bytep));
-
-	data.resize(rowbytes * height);
-
-	for (U i = 0; i < height; ++i)
-		rowPointers[height - 1 - i] = &data[i * rowbytes];
-
-	png_read_image(pngPtr, &rowPointers[0]);
-
-	// Finalize
-	//
-	switch(colorFormat)
-	{
-	case PNG_COLOR_TYPE_GRAY:
-		bpp = 8;
-		break;
-	case PNG_COLOR_TYPE_RGB:
-		bpp = 24;
-		break;
-	case PNG_COLOR_TYPE_RGBA:
-		bpp = 32;
-		break;
-	default:
-		err = "See file";
-		goto cleanup;
-	}
-
-	ok = true;
-
-	// Cleanup
-	//
-cleanup:
-
-	if(pngPtr)
-	{
-		if(infoPtr)
-		{
-			png_destroy_read_struct(&pngPtr, &infoPtr, NULL);
-		}
-		else
-		{
-			png_destroy_read_struct(&pngPtr, NULL, NULL);
-		}
-	}
-
-	if(file)
-	{
-		fclose(file);
-	}
-
-	return ok;
 }
 
 //==============================================================================
@@ -718,31 +471,6 @@ void Image::load(const char* filename)
 				ANKI_ASSERT(0);
 			}
 		}
-		else if(strcmp(ext, "png") == 0)
-		{
-			std::string err;
-			surfaces.resize(1);
-			mipLevels = 1;
-			depth = 1;
-			if(!loadPng(filename, err, bpp, surfaces[0].width, 
-				surfaces[0].height, surfaces[0].data))
-			{
-				throw ANKI_EXCEPTION(err);
-			}
-
-			if(bpp == 32)
-			{
-				colorFormat = CF_RGBA8;
-			}
-			else if(bpp == 24)
-			{
-				colorFormat = CF_RGB8;
-			}
-			else
-			{
-				throw ANKI_EXCEPTION("Unsupported color type");
-			}
-		}
 		else if(strcmp(ext, "ankitex") == 0)
 		{
 #if 0

+ 1 - 0
src/resource/Material.cpp

@@ -1,6 +1,7 @@
 #include "anki/resource/Material.h"
 #include "anki/resource/MaterialShaderProgramCreator.h"
 #include "anki/core/App.h"
+#include "anki/core/Logger.h"
 #include "anki/resource/ShaderProgramResource.h"
 #include "anki/resource/TextureResource.h"
 #include "anki/util/File.h"

+ 7 - 3
src/resource/ResourceManager.cpp

@@ -21,10 +21,14 @@ ResourceManager::ResourceManager()
 	else
 	{
 		// Assume working directory
-#if ANKI_POSIX
-		dataPath = "./";
+#if ANKI_OS == ANKI_OS_ANDROID
+		dataPath = "$";
 #else
+#	if ANKI_POSIX
+		dataPath = "./";
+#	else
 		dataPath = ".\\";
+#	endif
 #endif
 	}
 }
@@ -42,7 +46,7 @@ std::string ResourceManager::fixResourcePath(const char* filename) const
 	}
 	else
 	{
-		newFname = ResourceManagerSingleton::get().getDataPath() + filename;
+		newFname = dataPath + filename;
 	}
 
 	return newFname;

+ 13 - 0
src/util/Assert.cpp

@@ -2,6 +2,9 @@
 #include "anki/util/System.h"
 #include <cstdlib>
 #include <iostream>
+#if ANKI_OS == ANKI_OS_ANDROID
+#	include <android/log.h>
+#endif
 
 namespace anki {
 
@@ -13,9 +16,19 @@ void akassert(bool expr, const char* exprTxt, const char* file, int line,
 {
 	if(!expr)
 	{
+#if ANKI_OS == ANKI_OS_LINUX
 		std::cerr << "\033[1;31m(" << file << ":" << line << " "
 			<< func << ") " << "Assertion failed: " << exprTxt << "\033[0m"
 			<< std::endl;
+#elif ANKI_OS == ANKI_OS_ANDROID
+		__android_log_print(ANDROID_LOG_ERROR, "AnKi" 
+			"(%s:%d %s) Assertion failed: %s", file, line,
+			func, exprTxt);
+#else
+		std::cerr << "(" << file << ":" << line << " "
+			<< func << ") " << "Assertion failed: " << exprTxt
+			<< std::endl;
+#endif
 
 #if ANKI_CPU_ARCH == ANKI_CPU_ARCH_INTEL
 		asm("int $3");

+ 195 - 92
src/util/File.cpp

@@ -5,6 +5,9 @@
 #include <cstring>
 #include <cstdarg>
 #include <contrib/minizip/unzip.h>
+#if ANKI_OS == ANKI_OS_ANDROID
+#	include <android/asset_manager.h>
+#endif
 
 namespace anki {
 
@@ -12,97 +15,101 @@ namespace anki {
 // File                                                                        =
 //==============================================================================
 
-//==============================================================================
-File::~File()
-{
-	if(file)
-	{
-		if(flags & FT_C)
-		{
-			fclose((FILE*)file);
-		}
-		else if(flags & FT_ZIP)
-		{
-			ANKI_ASSERT(0 && "Not implemented");
-		}
-		else
-		{
-			ANKI_ASSERT(0);
-		}
-	}
-}
+#if ANKI_OS == ANKI_OS_ANDROID
+AAssetManager* File::andAssetManager = nullptr;
+#endif
 
 //==============================================================================
-File::Endianness File::getMachineEndianness()
+File::~File()
 {
-	I32 num = 1;
-	if(*(char*)&num == 1)
-	{
-		return E_LITTLE_ENDIAN;
-	}
-	else
-	{
-		return E_BIG_ENDIAN;
-	}
+	close();
 }
 
 //==============================================================================
-void File::open(const char* filename, U8 flags_)
+void File::open(const char* filename, U16 flags_)
 {
 	ANKI_ASSERT(filename);
+	ANKI_ASSERT(strlen(filename) > 0);
 	ANKI_ASSERT(file == nullptr && flags == 0);
 
+	// Only these flags are accepted
 	ANKI_ASSERT((flags_ & (OF_READ | OF_WRITE | OF_APPEND | OF_BINARY 
 		| E_LITTLE_ENDIAN | E_BIG_ENDIAN)) != 0);
 
+	// Cannot be both
 	ANKI_ASSERT((flags_ & OF_READ) != (flags_ & OF_WRITE));
 
 	//
 	// In the following lines determine the file type and open it
 	//
 
-	const char* aext = ".ankizip";
-	const char* ptrToArchiveExt = strstr(filename, aext);
-
-	if(ptrToArchiveExt == nullptr)
+#if ANKI_OS == ANKI_OS_ANDROID
+	if(filename[0] == '$')
 	{
-		// It's a C file
-		openCFile(filename, flags_);
+		openAndFile(filename, flags_);
 	}
 	else
+#endif
 	{
-		// Maybe it's a file in a zipped archive
+		const char* aext = ".ankizip";
+		const char* ptrToArchiveExt = strstr(filename, aext);
 
-		PtrSize fnameLen = strlen(filename);
-		PtrSize extLen = strlen(aext);
-		PtrSize archLen = (PtrSize)(ptrToArchiveExt - filename) + extLen;
-
-		if(archLen + 1 >= fnameLen)
+		if(ptrToArchiveExt == nullptr)
 		{
-			throw ANKI_EXCEPTION("Wrong file inside the archive");
-		}
-
-		std::string archive(filename, archLen);
-
-		if(directoryExists(archive.c_str()))
-		{
-			// It's a directory so failback to C file
+			// It's a C file
 			openCFile(filename, flags_);
 		}
 		else
 		{
-			// It's a ziped file
+			// Maybe it's a file in a zipped archive
 
-			std::string filenameInArchive(
-				filename + archLen + 1, fnameLen - archLen);
+			PtrSize fnameLen = strlen(filename);
+			PtrSize extLen = strlen(aext);
+			PtrSize archLen = (PtrSize)(ptrToArchiveExt - filename) + extLen;
 
-			openZipFile(archive.c_str(), filenameInArchive.c_str(), flags_);
+			if(archLen + 1 >= fnameLen)
+			{
+				throw ANKI_EXCEPTION("Wrong file inside the archive");
+			}
+
+			std::string archive(filename, archLen);
+
+			if(directoryExists(archive.c_str()))
+			{
+				// It's a directory so failback to C file
+				openCFile(filename, flags_);
+			}
+			else
+			{
+				// It's a ziped file
+
+				std::string filenameInArchive(
+					filename + archLen + 1, fnameLen - archLen);
+
+				openZipFile(archive.c_str(), filenameInArchive.c_str(), flags_);
+			}
 		}
 	}
+
+	//
+	// Set endianess
+	//
+
+	// If the open() DIDN'T provided us the file endianess 
+	if((flags_ & (E_BIG_ENDIAN | E_LITTLE_ENDIAN)) == 0)
+	{
+		// Set the machine's endianness
+		flags |= getMachineEndianness();
+	}
+	else
+	{
+		// Else just make sure that only one of the flags is set
+		ANKI_ASSERT((flags_ & E_BIG_ENDIAN) != (flags_ & E_LITTLE_ENDIAN));
+	}
 }
 
 //==============================================================================
-void File::openCFile(const char* filename, U8 flags_)
+void File::openCFile(const char* filename, U16 flags_)
 {
 	const char* openMode;
 
@@ -132,28 +139,21 @@ void File::openCFile(const char* filename, U8 flags_)
 	}
 
 	flags = flags_ | FT_C;
-
-	// If the open() DIDN'T provided us the file endianess 
-	if((flags_ & (E_BIG_ENDIAN | E_LITTLE_ENDIAN)) == 0)
-	{
-		// Set the machine's endianness
-		flags |= getMachineEndianness();
-	}
-	else
-	{
-		// Else just make sure that just one of the flags is set
-		ANKI_ASSERT((flags_ & E_BIG_ENDIAN) != (flags_ & E_LITTLE_ENDIAN));
-	}
 }
 
 //==============================================================================
-void File::openZipFile(const char* archive, const char* archived, U8 flags_)
+void File::openZipFile(const char* archive, const char* archived, U16 flags_)
 {
 	if(flags_ & OF_WRITE)
 	{
 		throw ANKI_EXCEPTION("Cannot write inside archives");
 	}
 
+	if(!(flags_ & OF_READ))
+	{
+		throw ANKI_EXCEPTION("Missing OF_READ flag");
+	}
+
 	// Open archive
 	unzFile zfile = unzOpen(archive);
 	if(zfile == nullptr)
@@ -182,21 +182,57 @@ void File::openZipFile(const char* archive, const char* archived, U8 flags_)
 }
 
 //==============================================================================
-void File::close()
+#if ANKI_OS == ANKI_OS_ANDROID
+void File::openAndFile(const char* filename, U16 flags_)
 {
-	ANKI_ASSERT(file);
+	if(flags_ & OF_WRITE)
+	{
+		throw ANKI_EXCEPTION("Cannot write inside archives");
+	}
 
-	if(flags & FT_C)
+	if(!(flags_ & OF_READ))
 	{
-		fclose((FILE*)file);
+		throw ANKI_EXCEPTION("Missing OF_READ flag");
 	}
-	else if(flags & FT_ZIP)
+
+	// Open file
+	ANKI_ASSERT(andAssetManager != nullptr 
+		&& "You should call setAndroidAssetManager() on engine initialization");
+	file = AAssetManager_open(
+		andAssetManager, filename + 1, AASSET_MODE_STREAMING);
+
+	if(file == nullptr)
 	{
-		unzClose(file);
+		throw ANKI_EXCEPTION("Failed to open file");
 	}
-	else
+
+	flags = flags_ | FT_SPECIAL;
+}
+#endif
+
+//==============================================================================
+void File::close()
+{
+	if(file)
 	{
-		ANKI_ASSERT(0);
+		if(flags & FT_C)
+		{
+			fclose((FILE*)file);
+		}
+		else if(flags & FT_ZIP)
+		{
+			unzClose(file);
+		}
+#if ANKI_OS == ANKI_OS_ANDROID
+		else if(flags & FT_SPECIAL)
+		{
+			AAsset_close((AAsset*)file);
+		}
+#endif
+		else
+		{
+			ANKI_ASSERT(0);
+		}
 	}
 
 	file = nullptr;
@@ -211,7 +247,7 @@ void File::read(void* buff, PtrSize size)
 	ANKI_ASSERT(file);
 	ANKI_ASSERT(flags & OF_READ);
 
-	PtrSize readSize = 0;
+	I64 readSize = 0;
 
 	if(flags & FT_C)
 	{
@@ -221,12 +257,18 @@ void File::read(void* buff, PtrSize size)
 	{
 		readSize = unzReadCurrentFile(file, buff, size);
 	}
+#if ANKI_OS == ANKI_OS_ANDROID
+	else if(flags & FT_SPECIAL)
+	{
+		readSize = AAsset_read((AAsset*)file, buff, size);
+	}
+#endif
 	else
 	{
 		ANKI_ASSERT(0);
 	}
 
-	if(size != readSize)
+	if((I64)size != readSize)
 	{
 		throw ANKI_EXCEPTION("File read failed");
 	}
@@ -244,19 +286,23 @@ void File::readAllText(std::string& txt)
 	{
 		// Get file size
 		fseek((FILE*)file, 0, SEEK_END);
-		PtrSize size = ftell((FILE*)file);
+		I64 size = ftell((FILE*)file);
+		if(size < 1)
+		{
+			throw ANKI_EXCEPTION("ftell() failed");
+		}
 		rewind((FILE*)file);
 
 		// Read and write
-		txt.resize(size);
+		txt.resize(size + 1);
 		PtrSize readSize = fread(&txt[0], 1, size, (FILE*)file);
-		(void)readSize;
-		ANKI_ASSERT(readSize == size);
+		ANKI_ASSERT(readSize == (PtrSize)size);
+		txt[readSize] = '\0';
 	}
 	else if(flags & FT_ZIP)
 	{
 		char buff[256];
-		I readSize;
+		I64 readSize;
 
 		while(true)
 		{
@@ -278,6 +324,19 @@ void File::readAllText(std::string& txt)
 			throw ANKI_EXCEPTION("unzReadCurrentFile() failed");
 		}
 	}
+#if ANKI_OS == ANKI_OS_ANDROID
+	else if(flags & FT_SPECIAL)
+	{
+		PtrSize size = AAsset_getLength((AAsset*)file);
+		AAsset_seek((AAsset*)file, 0, SEEK_SET);
+
+		txt.resize(size + 1);
+		I readSize = AAsset_read((AAsset*)file, &txt[0], size);
+		ANKI_ASSERT((PtrSize)readSize == size);
+
+		txt[readSize] = '\0';
+	}
+#endif
 	else
 	{
 		ANKI_ASSERT(0);
@@ -313,9 +372,15 @@ void File::readAllTextLines(StringList& lines)
 			}			
 		}
 	}
-	else if(flags & FT_ZIP)
+	else if(flags & FT_ZIP
+#if ANKI_OS == ANKI_OS_ANDROID
+		|| flags & FT_SPECIAL
+#endif
+		)
 	{
-		ANKI_ASSERT(0 && "Not implemented");
+		std::string txt;
+		readAllText(txt);
+		lines = StringList::splitString(txt.c_str(), '\n');
 	}
 	else
 	{
@@ -348,12 +413,12 @@ U32 File::readU32()
 	else if(machineEndianness == E_BIG_ENDIAN 
 		&& fileEndianness == E_LITTLE_ENDIAN)
 	{
-		U8* c = (U8*)&out;
+		U16* c = (U16*)&out;
 		out = (c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
 	}
 	else
 	{
-		U8* c = (U8*)&out;
+		U16* c = (U16*)&out;
 		out = ((c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]);
 	}
 
@@ -389,7 +454,11 @@ void File::write(void* buff, PtrSize size)
 			throw ANKI_EXCEPTION("Failed to write on file");
 		}
 	}
-	else if(flags & FT_ZIP)
+	else if(flags & FT_ZIP
+#if ANKI_OS == ANKI_OS_ANDROID
+		|| flags & FT_SPECIAL
+#endif
+		)
 	{
 		throw ANKI_EXCEPTION("Writting to archives is not supported");
 	}
@@ -415,7 +484,11 @@ void File::writeText(const char* format, ...)
 	{
 		vfprintf((FILE*)file, format, args);
 	}
-	else if(flags & FT_ZIP)
+	else if(flags & FT_ZIP
+#if ANKI_OS == ANKI_OS_ANDROID
+		|| flags & FT_SPECIAL
+#endif
+		)
 	{
 		throw ANKI_EXCEPTION("Writting to archives is not supported");
 	}
@@ -448,18 +521,48 @@ void File::seek(PtrSize offset, SeekOrigin origin)
 			if(unzCloseCurrentFile(file)
 				|| unzOpenCurrentFile(file))
 			{
-				throw ANKI_EXCEPTION("Rewinde failed");
+				throw ANKI_EXCEPTION("Rewind failed");
 			}
-			
-			// XXX
+		}
+
+		// Move forward by reading dummy data
+		char buff[256];
+		while(offset != 0)
+		{
+			PtrSize toRead = std::min(offset, sizeof(buff));
+			read(buff, toRead);
+			offset -= toRead;
 		}
 	}
+#if ANKI_OS == ANKI_OS_ANDROID
+	else if(flags & FT_SPECIAL)
+	{
+		if(AAsset_seek((AAsset*)file, offset, origin) != 0)
+		{
+			throw ANKI_EXCEPTION("AAsset_seek() failed");
+		}
+	}
+#endif
 	else
 	{
 		ANKI_ASSERT(0);
 	}
 }
 
+//==============================================================================
+File::Endianness File::getMachineEndianness()
+{
+	I32 num = 1;
+	if(*(char*)&num == 1)
+	{
+		return E_LITTLE_ENDIAN;
+	}
+	else
+	{
+		return E_BIG_ENDIAN;
+	}
+}
+
 //==============================================================================
 const char* File::getFileExtension(const char* filename)
 {

+ 1 - 1
src/util/FilePosix.cpp

@@ -5,7 +5,7 @@
 #include <cstring>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <ftw.h>
+//#include <ftw.h>
 #include <cerrno>
 
 namespace anki {

+ 7 - 3
src/util/System.cpp

@@ -3,12 +3,16 @@
 
 #if ANKI_POSIX
 #	include <unistd.h>
-#	include <execinfo.h>
 #	include <signal.h>
 #else
 #	error "Unimplemented"
 #endif
 
+// For print backtrace
+#if ANKI_POSIX && ANKI_OS != ANKI_OS_ANDROID
+#	include <execinfo.h>
+#endif
+
 namespace anki {
 
 //==============================================================================
@@ -24,7 +28,7 @@ U32 getCpuCoresCount()
 //==============================================================================
 void printBacktrace()
 {
-#if ANKI_POSIX
+#if ANKI_POSIX && ANKI_OS != ANKI_OS_ANDROID
 	void *array[10];
 	size_t size;
 
@@ -34,7 +38,7 @@ void printBacktrace()
 	// print out all the frames to stderr
 	backtrace_symbols_fd(array, size, 2);	
 #else
-#	error "Unimplemented"
+	// No nothing
 #endif
 }
 

+ 3 - 2
testapp/Main.cpp

@@ -460,7 +460,6 @@ void mainLoop()
 		// Update
 		//
 		InputSingleton::get().handleEvents();
-		InputSingleton::get().moveMouse(Vec2(0.0));
 		mainLoopExtra();
 		SceneGraphSingleton::get().update(
 			prevUpdateTime, crntTime, MainRendererSingleton::get());
@@ -516,7 +515,7 @@ void initSubsystems(int argc, char* argv[])
 #endif
 
 	// App
-	AppSingleton::get().init(argc, argv);
+	AppSingleton::get().init(nullptr);
 
 	// Window
 	NativeWindowInitializer nwinit;
@@ -536,7 +535,9 @@ void initSubsystems(int argc, char* argv[])
 
 	// Input
 	InputSingleton::get().init(win);
+	InputSingleton::get().lockCursor(true);
 	InputSingleton::get().hideCursor(true);
+	InputSingleton::get().moveCursor(Vec2(0.0));
 
 	// Main renderer
 	RendererInitializer initializer;