mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-25 06:19:51 +00:00
Merge pull request #7982 from hrydgard/remove-unused
Get rid of a ton of unused code in ext/native
This commit is contained in:
commit
5e640a3c40
@ -423,11 +423,6 @@ add_library(rg_etc1 STATIC
|
||||
ext/native/ext/rg_etc1/rg_etc1.h)
|
||||
include_directories(ext/native/ext/rg_etc1)
|
||||
|
||||
add_library(stb_vorbis STATIC
|
||||
ext/native/ext/stb_vorbis/stb_vorbis.c
|
||||
ext/native/ext/stb_vorbis/stb_vorbis.h)
|
||||
include_directories(ext/native/ext/stb_vorbis)
|
||||
|
||||
if(USE_FFMPEG)
|
||||
if(USE_SYSTEM_FFMPEG)
|
||||
find_package(FFMPEG)
|
||||
@ -876,28 +871,17 @@ add_library(native STATIC
|
||||
${nativeExtra}
|
||||
ext/native/base/backtrace.cpp
|
||||
ext/native/base/backtrace.h
|
||||
ext/native/audio/mixer.cpp
|
||||
ext/native/audio/mixer.h
|
||||
ext/native/audio/wav_read.cpp
|
||||
ext/native/audio/wav_read.h
|
||||
ext/native/base/basictypes.h
|
||||
ext/native/base/buffer.cpp
|
||||
ext/native/base/buffer.h
|
||||
ext/native/base/color.h
|
||||
ext/native/base/colorutil.cpp
|
||||
ext/native/base/colorutil.h
|
||||
ext/native/base/display.cpp
|
||||
ext/native/base/display.h
|
||||
ext/native/base/error_context.cpp
|
||||
ext/native/base/error_context.h
|
||||
ext/native/base/fastlist.h
|
||||
ext/native/base/fastlist_test.cpp
|
||||
ext/native/base/functional.h
|
||||
ext/native/base/linked_ptr.h
|
||||
ext/native/base/logging.h
|
||||
ext/native/base/mutex.h
|
||||
ext/native/base/scoped_ptr.h
|
||||
ext/native/base/stats.h
|
||||
ext/native/base/stringutil.cpp
|
||||
ext/native/base/stringutil.h
|
||||
ext/native/base/timeutil.cpp
|
||||
@ -910,8 +894,6 @@ add_library(native STATIC
|
||||
ext/native/ext/vjson/block_allocator.h
|
||||
ext/native/file/chunk_file.cpp
|
||||
ext/native/file/chunk_file.h
|
||||
ext/native/file/dialog.cpp
|
||||
ext/native/file/dialog.h
|
||||
ext/native/file/easy_file.cpp
|
||||
ext/native/file/easy_file.h
|
||||
ext/native/file/fd_util.cpp
|
||||
@ -930,13 +912,8 @@ add_library(native STATIC
|
||||
ext/native/gfx/gl_debug_log.h
|
||||
ext/native/gfx/gl_lost_manager.cpp
|
||||
ext/native/gfx/gl_lost_manager.h
|
||||
ext/native/gfx/texture.cpp
|
||||
ext/native/gfx/texture.h
|
||||
ext/native/gfx/texture_atlas.cpp
|
||||
ext/native/gfx/texture_atlas.h
|
||||
# ext/native/gfx/texture_dx11.cpp
|
||||
ext/native/gfx/texture_gen.cpp
|
||||
ext/native/gfx/texture_gen.h
|
||||
ext/native/gfx_es2/draw_buffer.cpp
|
||||
ext/native/gfx_es2/draw_buffer.h
|
||||
ext/native/gfx_es2/draw_text.cpp
|
||||
@ -945,8 +922,6 @@ add_library(native STATIC
|
||||
ext/native/gfx_es2/gpu_features.h
|
||||
ext/native/gfx_es2/glsl_program.cpp
|
||||
ext/native/gfx_es2/glsl_program.h
|
||||
ext/native/gfx_es2/vertex_format.cpp
|
||||
ext/native/gfx_es2/vertex_format.h
|
||||
ext/native/gfx_es2/gl3stub.c
|
||||
ext/native/gfx_es2/gl3stub.h
|
||||
ext/native/i18n/i18n.cpp
|
||||
@ -968,8 +943,6 @@ add_library(native STATIC
|
||||
ext/native/math/curves.h
|
||||
ext/native/math/expression_parser.cpp
|
||||
ext/native/math/expression_parser.h
|
||||
ext/native/math/lin/aabb.cpp
|
||||
ext/native/math/lin/aabb.h
|
||||
ext/native/math/lin/matrix4x4.cpp
|
||||
ext/native/math/lin/matrix4x4.h
|
||||
ext/native/math/lin/plane.cpp
|
||||
@ -981,6 +954,8 @@ add_library(native STATIC
|
||||
ext/native/math/lin/vec3.h
|
||||
ext/native/math/math_util.cpp
|
||||
ext/native/math/math_util.h
|
||||
ext/native/net/http_server.cpp
|
||||
ext/native/net/http_server.h
|
||||
ext/native/net/http_client.cpp
|
||||
ext/native/net/http_client.h
|
||||
ext/native/net/resolve.cpp
|
||||
@ -1012,15 +987,8 @@ add_library(native STATIC
|
||||
ext/native/ui/viewgroup.h
|
||||
ext/native/ui/virtual_input.cpp
|
||||
ext/native/ui/virtual_input.h
|
||||
ext/native/util/bits/bits.cpp
|
||||
ext/native/util/bits/bits.h
|
||||
ext/native/util/bits/hamming.h
|
||||
ext/native/util/bits/varint.cpp
|
||||
ext/native/util/bits/varint.h
|
||||
ext/native/util/hash/hash.cpp
|
||||
ext/native/util/hash/hash.h
|
||||
ext/native/util/random/perlin.cpp
|
||||
ext/native/util/random/perlin.h
|
||||
ext/native/util/random/rng.h
|
||||
ext/native/util/text/utf8.h
|
||||
ext/native/util/text/utf8.cpp
|
||||
@ -1037,7 +1005,7 @@ if (LINUX AND NOT ANDROID)
|
||||
SET(RT_LIB rt)
|
||||
endif()
|
||||
|
||||
target_link_libraries(native ${LIBZIP_LIBRARY} ${ZLIB_LIBRARY} ${PNG_LIBRARY} rg_etc1 vjson stb_vorbis snappy udis86 ${RT_LIB} ${GLEW_LIBRARIES})
|
||||
target_link_libraries(native ${LIBZIP_LIBRARY} ${ZLIB_LIBRARY} ${PNG_LIBRARY} rg_etc1 vjson snappy udis86 ${RT_LIB} ${GLEW_LIBRARIES})
|
||||
|
||||
if(ANDROID)
|
||||
target_link_libraries(native log EGL)
|
||||
|
@ -36,12 +36,6 @@ SOURCES += $$P/ext/native/ext/jpge/*.cpp
|
||||
HEADERS += $$P/ext/native/ext/jpge/*.h
|
||||
INCLUDEPATH += $$P/ext/native/ext/jpge
|
||||
|
||||
# Stb_vorbis
|
||||
|
||||
SOURCES += $$P/ext/native/ext/stb_vorbis/stb_vorbis.c
|
||||
HEADERS += $$P/ext/native/ext/stb_vorbis/stb_vorbis.h
|
||||
INCLUDEPATH += $$P/ext/native/ext/stb_vorbis
|
||||
|
||||
# Snappy
|
||||
!exists( /usr/include/snappy-c.h ) {
|
||||
SOURCES += $$P/ext/snappy/*.cpp
|
||||
@ -77,23 +71,19 @@ win32|contains(QT_CONFIG, no-zlib) {
|
||||
|
||||
# Native
|
||||
|
||||
SOURCES += $$P/ext/native/audio/*.cpp \
|
||||
SOURCES += \
|
||||
$$P/ext/native/base/backtrace.cpp \
|
||||
$$P/ext/native/base/buffer.cpp \
|
||||
$$P/ext/native/base/colorutil.cpp \
|
||||
$$P/ext/native/base/compat.cpp \
|
||||
$$P/ext/native/base/display.cpp \
|
||||
$$P/ext/native/base/error_context.cpp \
|
||||
$$P/ext/native/base/fastlist_test.cpp \
|
||||
$$P/ext/native/base/stringutil.cpp \
|
||||
$$P/ext/native/base/timeutil.cpp \
|
||||
$$P/ext/native/data/compression.cpp \
|
||||
$$P/ext/native/file/*.cpp \
|
||||
$$P/ext/native/gfx/gl_debug_log.cpp \
|
||||
$$P/ext/native/gfx/gl_lost_manager.cpp \
|
||||
$$P/ext/native/gfx/texture.cpp \
|
||||
$$P/ext/native/gfx/texture_atlas.cpp \
|
||||
$$P/ext/native/gfx/texture_gen.cpp \
|
||||
$$P/ext/native/gfx_es2/*.cpp \
|
||||
$$P/ext/native/gfx_es2/*.c \
|
||||
$$P/ext/native/i18n/*.cpp \
|
||||
@ -110,29 +100,22 @@ SOURCES += $$P/ext/native/audio/*.cpp \
|
||||
$$P/ext/native/thin3d/thin3d_gl.cpp \
|
||||
$$P/ext/native/thread/*.cpp \
|
||||
$$P/ext/native/ui/*.cpp \
|
||||
$$P/ext/native/util/bits/*.cpp \
|
||||
$$P/ext/native/util/hash/hash.cpp \
|
||||
$$P/ext/native/util/random/perlin.cpp \
|
||||
$$P/ext/native/util/text/utf8.cpp \
|
||||
$$P/ext/native/util/text/parsers.cpp
|
||||
|
||||
armv7: SOURCES += $$files($$P/ext/native/math/fast/fast_matrix_neon.S)
|
||||
|
||||
|
||||
HEADERS += $$P/ext/native/audio/*.h \
|
||||
HEADERS += \
|
||||
$$P/ext/native/base/backtrace.h \
|
||||
$$P/ext/native/base/basictypes.h \
|
||||
$$P/ext/native/base/buffer.h \
|
||||
$$P/ext/native/base/color.h \
|
||||
$$P/ext/native/base/colorutil.h \
|
||||
$$P/ext/native/base/display.h \
|
||||
$$P/ext/native/base/error_context.h \
|
||||
$$P/ext/native/base/fastlist.h \
|
||||
$$P/ext/native/base/linked_ptr.h \
|
||||
$$P/ext/native/base/logging.h \
|
||||
$$P/ext/native/base/mutex.h \
|
||||
$$P/ext/native/base/scoped_ptr.h \
|
||||
$$P/ext/native/base/stats.h \
|
||||
$$P/ext/native/base/stringutil.h \
|
||||
$$P/ext/native/base/timeutil.h \
|
||||
$$P/ext/native/data/compression.h \
|
||||
@ -149,7 +132,6 @@ HEADERS += $$P/ext/native/audio/*.h \
|
||||
$$P/ext/native/profiler/profiler.h \
|
||||
$$P/ext/native/thread/*.h \
|
||||
$$P/ext/native/ui/*.h \
|
||||
$$P/ext/native/util/bits/*.h \
|
||||
$$P/ext/native/util/hash/hash.h \
|
||||
$$P/ext/native/util/random/*.h \
|
||||
$$P/ext/native/util/text/utf8.h \
|
||||
|
@ -51,7 +51,6 @@
|
||||
#include "gfx_es2/draw_text.h"
|
||||
#include "gfx_es2/gpu_features.h"
|
||||
#include "gfx/gl_lost_manager.h"
|
||||
#include "gfx/texture.h"
|
||||
#include "i18n/i18n.h"
|
||||
#include "input/input_state.h"
|
||||
#include "math/fast/fast_math.h"
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "file/zip_read.h"
|
||||
#include "input/input_state.h"
|
||||
#include "profiler/profiler.h"
|
||||
#include "audio/mixer.h"
|
||||
#include "math/math_util.h"
|
||||
#include "net/resolve.h"
|
||||
#include "android/jni/native_audio.h"
|
||||
|
@ -1,92 +0,0 @@
|
||||
/usr/bin/c++
|
||||
-std=gnu++0x
|
||||
CMakeFiles/ppsspp.dir/home/artart78/prog/psp/ppsspp/android/jni/NativeApp.cpp.o
|
||||
CMakeFiles/ppsspp.dir/home/artart78/prog/psp/ppsspp/android/jni/EmuScreen.cpp.o
|
||||
CMakeFiles/ppsspp.dir/home/artart78/prog/psp/ppsspp/android/jni/MenuScreens.cpp.o
|
||||
CMakeFiles/ppsspp.dir/home/artart78/prog/psp/ppsspp/android/jni/GamepadEmu.cpp.o
|
||||
CMakeFiles/ppsspp.dir/home/artart78/prog/psp/ppsspp/android/jni/UIShader.cpp.o
|
||||
CMakeFiles/ppsspp.dir/home/artart78/prog/psp/ppsspp/android/jni/ui_atlas.cpp.o
|
||||
CMakeFiles/ppsspp.dir/home/artart78/prog/psp/ppsspp/native/base/PCMain.cpp.o
|
||||
-o
|
||||
ppsspp
|
||||
-rdynamic
|
||||
-L/usr/local/lib
|
||||
-L/opt/local/lib
|
||||
-L/usr/X11/lib
|
||||
-Wl,-Bstatic
|
||||
-lSDLmain
|
||||
-Wl,-Bdynamic
|
||||
-lSDL
|
||||
-lpthread
|
||||
-lGLU
|
||||
-lGL
|
||||
-lSM
|
||||
-lICE
|
||||
-lX11
|
||||
-lXext
|
||||
-lGLEW
|
||||
kirk/libkirk.a
|
||||
file/libfile.a
|
||||
kirk/libkirk.a
|
||||
math/liblin.a
|
||||
kirk/libkirk.a
|
||||
-lpng
|
||||
kirk/libkirk.a
|
||||
-lz
|
||||
kirk/libkirk.a
|
||||
gfx/libgfx.a
|
||||
kirk/libkirk.a
|
||||
gfx_es2/libgfx_es2.a
|
||||
kirk/libkirk.a
|
||||
etcpack/libetcdec.a
|
||||
kirk/libkirk.a
|
||||
image/libimage.a
|
||||
kirk/libkirk.a
|
||||
stb_image/libstb_image.a
|
||||
kirk/libkirk.a
|
||||
audio/libmixer.a
|
||||
kirk/libkirk.a
|
||||
net/libnet.a
|
||||
kirk/libkirk.a
|
||||
ui/libui.a
|
||||
kirk/libkirk.a
|
||||
profiler/libprofiler.a
|
||||
kirk/libkirk.a
|
||||
base/libtimeutil.a
|
||||
kirk/libkirk.a
|
||||
libzip/libzip.a
|
||||
kirk/libkirk.a
|
||||
base/libbase.a
|
||||
kirk/libkirk.a
|
||||
math/liblin.a
|
||||
kirk/libkirk.a
|
||||
vjson/libvjson.a
|
||||
kirk/libkirk.a
|
||||
stb_vorbis/libstb_vorbis.a
|
||||
kirk/libkirk.a
|
||||
sha1/libsha1.a
|
||||
kirk/libkirk.a
|
||||
jsonwriter/libjsonwriter.a
|
||||
kirk/libkirk.a
|
||||
Common/libcommon.a
|
||||
kirk/libkirk.a
|
||||
Core/libcore.a
|
||||
kirk/libkirk.a
|
||||
GPU/libgpu.a
|
||||
kirk/libkirk.a
|
||||
base/libbase.a
|
||||
kirk/libkirk.a
|
||||
Common/libcommon.a
|
||||
kirk/libkirk.a
|
||||
math/liblin.a
|
||||
kirk/libkirk.a
|
||||
gfx_es2/libgfx_es2.a
|
||||
kirk/libkirk.a
|
||||
file/libfile.a
|
||||
kirk/libkirk.a
|
||||
libzip/libzip.a
|
||||
kirk/libkirk.a
|
||||
gfx/libgfx.a
|
||||
kirk/libkirk.a
|
||||
-Wl,-rpath,/usr/local/lib:/opt/local/lib:/usr/X11/lib
|
||||
|
@ -7,15 +7,12 @@ include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := libnative
|
||||
LOCAL_ARM_MODE := arm
|
||||
LOCAL_SRC_FILES :=\
|
||||
audio/wav_read.cpp \
|
||||
audio/mixer.cpp.arm \
|
||||
base/backtrace.cpp \
|
||||
base/buffer.cpp \
|
||||
base/compat.cpp \
|
||||
base/display.cpp \
|
||||
base/timeutil.cpp \
|
||||
base/colorutil.cpp \
|
||||
base/error_context.cpp \
|
||||
base/stringutil.cpp \
|
||||
data/compression.cpp \
|
||||
ext/rg_etc1/rg_etc1.cpp \
|
||||
@ -39,10 +36,8 @@ LOCAL_SRC_FILES :=\
|
||||
ext/jpge/jpgd.cpp \
|
||||
ext/jpge/jpge.cpp \
|
||||
ext/sha1/sha1.cpp \
|
||||
ext/stb_vorbis/stb_vorbis.c.arm \
|
||||
ext/vjson/json.cpp \
|
||||
ext/vjson/block_allocator.cpp \
|
||||
file/dialog.cpp \
|
||||
file/fd_util.cpp \
|
||||
file/easy_file.cpp \
|
||||
file/chunk_file.cpp \
|
||||
@ -59,12 +54,10 @@ LOCAL_SRC_FILES :=\
|
||||
math/math_util.cpp \
|
||||
math/curves.cpp \
|
||||
math/expression_parser.cpp \
|
||||
math/lin/aabb.cpp.arm \
|
||||
math/lin/plane.cpp.arm \
|
||||
math/lin/quat.cpp.arm \
|
||||
math/lin/vec3.cpp.arm \
|
||||
math/lin/matrix4x4.cpp.arm \
|
||||
midi/midi_input.cpp \
|
||||
net/http_client.cpp \
|
||||
net/http_server.cpp \
|
||||
net/http_headers.cpp \
|
||||
@ -80,12 +73,9 @@ LOCAL_SRC_FILES :=\
|
||||
gfx_es2/gl3stub.c \
|
||||
gfx_es2/draw_buffer.cpp.arm \
|
||||
gfx_es2/draw_text.cpp.arm \
|
||||
gfx_es2/vertex_format.cpp \
|
||||
gfx/gl_debug_log.cpp \
|
||||
gfx/gl_lost_manager.cpp \
|
||||
gfx/texture.cpp \
|
||||
gfx/texture_atlas.cpp \
|
||||
gfx/texture_gen.cpp \
|
||||
image/zim_load.cpp \
|
||||
image/zim_save.cpp \
|
||||
image/png_load.cpp \
|
||||
@ -98,7 +88,6 @@ LOCAL_SRC_FILES :=\
|
||||
ui/ui_context.cpp \
|
||||
ui/screen.cpp \
|
||||
ui/virtual_input.cpp \
|
||||
util/random/perlin.cpp \
|
||||
util/text/utf8.cpp \
|
||||
util/text/parsers.cpp \
|
||||
util/hash/hash.cpp
|
||||
|
@ -1,50 +0,0 @@
|
||||
native
|
||||
======
|
||||
|
||||
This is my library of stuff that I use when writing C++ programs, mostly for Android but it's all written to enable easy portability between Android, Linux, Windows and MacOSX. The code is part ugly, part inconsistent but quite useful.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* JSON read/write (two libraries that should be made more similar)
|
||||
* basic OpenGL utility code, like compressed texture loading
|
||||
* 2D texture atlases and drawing code
|
||||
* ETC1 texture save/load support
|
||||
* basic logging
|
||||
* Really simple audio mixer with OGG sample support
|
||||
* RIFF file read/write
|
||||
* MIDI Input (only on Windows)
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
* The associated tools to create ZIM texture files and atlases do not yet live here but I might move them here eventually.
|
||||
* This library is not really meant to be a public library but I see no reason not to set it free.
|
||||
* Note that the included VS project is probably not very useful for you and you're likely better off making your own.
|
||||
* Don't complain about inconsistent naming etc - this consists of code that has been cobbled together from a variety of my projects through the years. Fashions come and go.
|
||||
|
||||
Licenses
|
||||
--------
|
||||
|
||||
This library, for my convenience, incorporates code from a variety of public domain or similarly-licensed code. This is the list:
|
||||
|
||||
* glew (GL extension wrangler), MIT license. TODO: should just use a submodule.
|
||||
* rg_etc1. ZLIB license.
|
||||
* sha1, public domain implementation by Dominik Reichl
|
||||
* vjson in a heavily modified form, originally by Ivan Vashchaev (TODO: break out into its own repo?)
|
||||
* libzip with attribution "Copyright (C) 1999-2007 Dieter Baron and Thomas Klausner"
|
||||
* stb_vorbis, public domain by Sean Barrett of RAD Tools
|
||||
|
||||
If you're not okay with the licenses above, don't use this code.
|
||||
|
||||
I hereby release all code here not under the licenses above under the MIT license.
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
If you find this useful for your own projects, drop me a line at hrydgard@gmail.com .
|
||||
|
||||
Henrik Rydgård
|
||||
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
set(SRCS
|
||||
mixer.cpp
|
||||
wav_read.cpp)
|
||||
|
||||
set(SRCS ${SRCS})
|
||||
|
||||
add_library(mixer STATIC ${SRCS})
|
||||
|
||||
if(UNIX)
|
||||
add_definitions(-fPIC)
|
||||
endif(UNIX)
|
@ -1,201 +0,0 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "audio/mixer.h"
|
||||
#include "audio/wav_read.h"
|
||||
#include "base/logging.h"
|
||||
#include "ext/stb_vorbis/stb_vorbis.h"
|
||||
#include "file/vfs.h"
|
||||
|
||||
// TODO:
|
||||
// * Vorbis streaming playback
|
||||
|
||||
struct ChannelEffectState {
|
||||
// Filter state
|
||||
};
|
||||
|
||||
enum CLIP_TYPE {
|
||||
CT_PCM16,
|
||||
CT_SYNTHFX,
|
||||
CT_VORBIS,
|
||||
// CT_PHOENIX?
|
||||
};
|
||||
|
||||
struct Clip {
|
||||
int type;
|
||||
|
||||
short *data;
|
||||
int length;
|
||||
int num_channels; // this is NOT stereo vs mono
|
||||
int sample_rate;
|
||||
int loop_start;
|
||||
int loop_end;
|
||||
};
|
||||
|
||||
// If current_clip == 0, the channel is free.
|
||||
|
||||
enum ClipPlaybackState {
|
||||
PB_STOPPED = 0,
|
||||
PB_PLAYING = 1,
|
||||
};
|
||||
|
||||
|
||||
struct Channel {
|
||||
const Clip *current_clip;
|
||||
// Playback state
|
||||
ClipPlaybackState state;
|
||||
int pos;
|
||||
PlayParams params;
|
||||
// Effect state
|
||||
ChannelEffectState effect_state;
|
||||
};
|
||||
|
||||
struct Mixer {
|
||||
Channel *channels;
|
||||
int sample_rate;
|
||||
int num_channels;
|
||||
int num_fixed_channels;
|
||||
};
|
||||
|
||||
Mixer *mixer_create(int sample_rate, int channels, int fixed_channels) {
|
||||
Mixer *mixer = new Mixer();
|
||||
memset(mixer, 0, sizeof(Mixer));
|
||||
mixer->channels = new Channel[channels];
|
||||
memset(mixer->channels, 0, sizeof(Channel) * channels);
|
||||
mixer->sample_rate = sample_rate;
|
||||
mixer->num_channels = channels;
|
||||
mixer->num_fixed_channels = fixed_channels;
|
||||
return mixer;
|
||||
}
|
||||
|
||||
void mixer_destroy(Mixer *mixer) {
|
||||
delete [] mixer->channels;
|
||||
delete mixer;
|
||||
}
|
||||
|
||||
static int get_free_channel(Mixer *mixer) {
|
||||
int chan_with_biggest_pos = -1;
|
||||
int biggest_pos = -1;
|
||||
for (int i = mixer->num_fixed_channels; i < mixer->num_channels; i++) {
|
||||
Channel *chan = &mixer->channels[i];
|
||||
if (!chan->current_clip) {
|
||||
return i;
|
||||
}
|
||||
if (chan->pos > biggest_pos) {
|
||||
biggest_pos = chan->pos;
|
||||
chan_with_biggest_pos = i;
|
||||
}
|
||||
}
|
||||
return chan_with_biggest_pos;
|
||||
}
|
||||
|
||||
Clip *clip_load(const char *filename) {
|
||||
short *data;
|
||||
int num_samples;
|
||||
int sample_rate, num_channels;
|
||||
|
||||
if (!strcmp(filename + strlen(filename) - 4, ".ogg")) {
|
||||
// Ogg file. For now, directly decompress, no streaming support.
|
||||
uint8_t *filedata;
|
||||
size_t size;
|
||||
filedata = VFSReadFile(filename, &size);
|
||||
num_samples = (int)stb_vorbis_decode_memory(filedata, (int)size, &num_channels, &data);
|
||||
if (num_samples <= 0)
|
||||
return NULL;
|
||||
sample_rate = 44100;
|
||||
ILOG("read ogg %s, length %i, rate %i", filename, num_samples, sample_rate);
|
||||
} else {
|
||||
// Wav file. Easy peasy.
|
||||
data = wav_read(filename, &num_samples, &sample_rate, &num_channels);
|
||||
if (!data) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Clip *clip = new Clip();
|
||||
clip->type = CT_PCM16;
|
||||
clip->data = data;
|
||||
clip->length = num_samples;
|
||||
clip->num_channels = num_channels;
|
||||
clip->sample_rate = sample_rate;
|
||||
clip->loop_start = 0;
|
||||
clip->loop_end = 0;
|
||||
return clip;
|
||||
}
|
||||
|
||||
void clip_destroy(Clip *clip) {
|
||||
if (clip) {
|
||||
free(clip->data);
|
||||
delete clip;
|
||||
} else {
|
||||
ELOG("Can't destroy zero clip");
|
||||
}
|
||||
}
|
||||
|
||||
const short *clip_data(const Clip *clip)
|
||||
{
|
||||
return clip->data;
|
||||
}
|
||||
|
||||
size_t clip_length(const Clip *clip) {
|
||||
return clip->length;
|
||||
}
|
||||
|
||||
void clip_set_loop(Clip *clip, int start, int end) {
|
||||
clip->loop_start = start;
|
||||
clip->loop_end = end;
|
||||
}
|
||||
|
||||
PlayParams *mixer_play_clip(Mixer *mixer, const Clip *clip, int channel) {
|
||||
if (channel == -1) {
|
||||
channel = get_free_channel(mixer);
|
||||
}
|
||||
|
||||
Channel *chan = &mixer->channels[channel];
|
||||
// Think about this order and make sure it's thread"safe" (not perfect but should not cause crashes).
|
||||
chan->pos = 0;
|
||||
chan->current_clip = clip;
|
||||
chan->state = PB_PLAYING;
|
||||
PlayParams *params = &chan->params;
|
||||
params->volume = 128;
|
||||
params->pan = 128;
|
||||
return params;
|
||||
}
|
||||
|
||||
void mixer_mix(Mixer *mixer, short *buffer, int num_samples) {
|
||||
// Clear the buffer.
|
||||
memset(buffer, 0, num_samples * sizeof(short) * 2);
|
||||
for (int i = 0; i < mixer->num_channels; i++) {
|
||||
Channel *chan = &mixer->channels[i];
|
||||
if (chan->state == PB_PLAYING) {
|
||||
const Clip *clip = chan->current_clip;
|
||||
if (clip->type == CT_PCM16) {
|
||||
// For now, only allow mono PCM
|
||||
CHECK(clip->num_channels == 1);
|
||||
if (true || chan->params.delta == 0) {
|
||||
// Fast playback of non pitched clips
|
||||
int cnt = num_samples;
|
||||
if (clip->length - chan->pos < cnt) {
|
||||
cnt = clip->length - chan->pos;
|
||||
}
|
||||
// TODO: Take pan into account.
|
||||
int left_volume = chan->params.volume;
|
||||
int right_volume = chan->params.volume;
|
||||
// TODO: NEONize. Can also make special loops for left_volume == right_volume etc.
|
||||
for (int s = 0; s < cnt; s++) {
|
||||
int cdata = clip->data[chan->pos];
|
||||
buffer[s * 2 + 0] += cdata * left_volume >> 8;
|
||||
buffer[s * 2 + 1] += cdata * right_volume >> 8;
|
||||
chan->pos++;
|
||||
}
|
||||
if (chan->pos >= clip->length) {
|
||||
chan->state = PB_STOPPED;
|
||||
chan->current_clip = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (clip->type == CT_VORBIS) {
|
||||
// For music
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
// Simple mixer intended for sound effects for games.
|
||||
// The clip loading code supports ogg SFX.
|
||||
|
||||
struct Mixer;
|
||||
struct Clip;
|
||||
struct Channel;
|
||||
|
||||
// This struct is public for easy manipulation of running channels.
|
||||
struct PlayParams {
|
||||
uint8_t volume; // 0-255
|
||||
uint8_t pan; // 0-255, 127 is dead center.
|
||||
int32_t delta;
|
||||
};
|
||||
|
||||
// Mixer
|
||||
// ==========================
|
||||
// For now, channels is required to be 2 (it specifies L/R, not mixing channels)
|
||||
Mixer *mixer_create(int sample_rate, int channels, int fixed_channels);
|
||||
void mixer_destroy(Mixer *mixer);
|
||||
|
||||
// Buffer must be r/w.
|
||||
void mixer_mix(Mixer *mixer, short *buffer, int num_samples);
|
||||
|
||||
|
||||
// Clip
|
||||
// ==========================
|
||||
Clip *clip_load(const char *filename);
|
||||
void clip_destroy(Clip *clip);
|
||||
|
||||
const short *clip_data(const Clip *clip);
|
||||
size_t clip_length(const Clip *clip);
|
||||
void clip_set_loop(int start, int end);
|
||||
|
||||
|
||||
// The returned PlayState pointer can be used to set the playback parameters,
|
||||
// but must not be kept around unless you are using a fixed channel.
|
||||
// Channel must be either -1 for auto assignment to a free channel, or less
|
||||
// than the number of fixed channels that the mixer was created with.
|
||||
PlayParams *mixer_play_clip(Mixer *mixer, const Clip *clip, int channel);
|
@ -1,70 +0,0 @@
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "audio/wav_read.h"
|
||||
#include "file/chunk_file.h"
|
||||
|
||||
short *wav_read(const char *filename,
|
||||
int *num_samples, int *sample_rate,
|
||||
int *num_channels)
|
||||
{
|
||||
ChunkFile cf(filename, true);
|
||||
if (cf.failed()) {
|
||||
WLOG("ERROR: Wave file %s could not be opened", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
short *data = 0;
|
||||
int samplesPerSec, avgBytesPerSec,wBlockAlign,wBytesPerSample;
|
||||
if (cf.descend('RIFF')) {
|
||||
cf.readInt(); //get past 'WAVE'
|
||||
if (cf.descend('fmt ')) { //enter the format chunk
|
||||
int temp = cf.readInt();
|
||||
int format = temp & 0xFFFF;
|
||||
if (format != 1) {
|
||||
cf.ascend();
|
||||
cf.ascend();
|
||||
ELOG("Error - bad format");
|
||||
return NULL;
|
||||
}
|
||||
*num_channels = temp >> 16;
|
||||
samplesPerSec = cf.readInt();
|
||||
avgBytesPerSec = cf.readInt();
|
||||
|
||||
temp = cf.readInt();
|
||||
wBlockAlign = temp & 0xFFFF;
|
||||
wBytesPerSample = temp >> 16;
|
||||
cf.ascend();
|
||||
// ILOG("got fmt data: %i", samplesPerSec);
|
||||
} else {
|
||||
ELOG("Error - no format chunk in wav");
|
||||
cf.ascend();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cf.descend('data')) { //enter the data chunk
|
||||
int numBytes = cf.getCurrentChunkSize();
|
||||
int numSamples = numBytes / wBlockAlign;
|
||||
data = (short *)malloc(sizeof(short) * numSamples * *num_channels);
|
||||
*num_samples = numSamples;
|
||||
if (wBlockAlign == 2 && *num_channels == 1) {
|
||||
cf.readData((uint8_t *)data,numBytes);
|
||||
} else {
|
||||
ELOG("Error - bad blockalign or channels");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
cf.ascend();
|
||||
} else {
|
||||
ELOG("Error - no data chunk in wav");
|
||||
cf.ascend();
|
||||
return NULL;
|
||||
}
|
||||
cf.ascend();
|
||||
} else {
|
||||
ELOG("Could not descend into RIFF file");
|
||||
return NULL;
|
||||
}
|
||||
*sample_rate = samplesPerSec;
|
||||
ILOG("read wav %s, length %i, rate %i", filename, *num_samples, *sample_rate);
|
||||
return data;
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
#include "base/basictypes.h"
|
||||
|
||||
// Allocates a buffer that should be freed using free().
|
||||
short *wav_read(const char *filename,
|
||||
int *num_samples, int *sample_rate,
|
||||
int *num_channels);
|
||||
// TODO: Non-allocating version.
|
@ -2,7 +2,6 @@ set(SRCS
|
||||
colorutil.cpp
|
||||
timeutil.cpp
|
||||
../thread/threadutil.cpp
|
||||
error_context.cpp
|
||||
display.cpp
|
||||
buffer.cpp
|
||||
backtrace.cpp)
|
||||
|
@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
typedef unsigned int Color;
|
||||
|
||||
//have to use a define to ensure constant folding.. with an inline I don't get that, sucks
|
||||
#define COLOR(i) (((i&0xFF) << 16) | (i & 0xFF00) | ((i & 0xFF0000) >> 16) | 0xFF000000)
|
||||
inline Color darkenColor(Color color) {
|
||||
return (color & 0xFF000000) | ((color >> 1)&0x7F7F7F);
|
||||
}
|
||||
inline Color whitenColor(Color color) {
|
||||
return ((color & 0xFF000000) | ((color >> 1)&0x7F7F7F)) + 0x7F7F7F;
|
||||
}
|
||||
inline Color colorInterpol(Color x, Color y, int n) {
|
||||
// TODO
|
||||
return x;
|
||||
}
|
@ -10,3 +10,17 @@ uint32_t alphaMul(uint32_t color, float alphaMul);
|
||||
uint32_t rgba(float r, float g, float b, float alpha);
|
||||
uint32_t rgba_clamp(float r, float g, float b, float alpha);
|
||||
uint32_t hsva(float h, float s, float v, float alpha);
|
||||
|
||||
typedef unsigned int Color;
|
||||
|
||||
#define COLOR(i) (((i&0xFF) << 16) | (i & 0xFF00) | ((i & 0xFF0000) >> 16) | 0xFF000000)
|
||||
inline Color darkenColor(Color color) {
|
||||
return (color & 0xFF000000) | ((color >> 1) & 0x7F7F7F);
|
||||
}
|
||||
inline Color whitenColor(Color color) {
|
||||
return ((color & 0xFF000000) | ((color >> 1) & 0x7F7F7F)) + 0x7F7F7F;
|
||||
}
|
||||
inline Color colorInterpol(Color x, Color y, int n) {
|
||||
// TODO
|
||||
return x;
|
||||
}
|
||||
|
@ -1,40 +0,0 @@
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/error_context.h"
|
||||
#include <vector>
|
||||
|
||||
// TODO: Fix this threadery
|
||||
#ifndef _WIN32
|
||||
#undef __THREAD
|
||||
#define __THREAD
|
||||
#endif
|
||||
|
||||
__THREAD std::vector<const char *> *_error_context_name;
|
||||
__THREAD std::vector<const char *> *_error_context_data;
|
||||
|
||||
_ErrorContext::_ErrorContext(const char *name, const char *data) {
|
||||
if (!_error_context_name) {
|
||||
_error_context_name = new std::vector<const char *>();
|
||||
_error_context_data = new std::vector<const char *>();
|
||||
_error_context_name->reserve(16);
|
||||
_error_context_data->reserve(16);
|
||||
}
|
||||
_error_context_name->push_back(name);
|
||||
_error_context_data->push_back(data);
|
||||
}
|
||||
|
||||
_ErrorContext::~_ErrorContext() {
|
||||
_error_context_name->pop_back();
|
||||
_error_context_data->pop_back();
|
||||
}
|
||||
|
||||
void _ErrorContext::Log(const char *message) {
|
||||
ILOG("EC: %s", message);
|
||||
for (size_t i = 0; i < _error_context_name->size(); i++) {
|
||||
if ((*_error_context_data)[i] != 0) {
|
||||
ILOG("EC: %s: %s", (*_error_context_name)[i], (*_error_context_data)[i]);
|
||||
} else {
|
||||
ILOG("EC: %s: %s", (*_error_context_name)[i], (*_error_context_data)[i]);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// do not inherit
|
||||
|
||||
// TODO: Have the crash handler investigate the error context.
|
||||
// Must only be constructed on the stack - DO NOT put these on the heap.
|
||||
class _ErrorContext
|
||||
{
|
||||
public:
|
||||
_ErrorContext(const char *name, const char *data = 0);
|
||||
~_ErrorContext();
|
||||
|
||||
// Logs the current context stack.
|
||||
static void Log(const char *message);
|
||||
};
|
||||
|
||||
#define ErrorContext(...) _ErrorContext __ec(__VA_ARGS__)
|
||||
#define LogErrorContext(msg) _ErrorContext::Log(msg)
|
@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// An inline fastlist is a fixed size array with a position counter.
|
||||
// Objects stored in a fastlist must be copyable.
|
||||
// [] returns the objects in consecutive order, up to and not including
|
||||
// the value of .size().
|
||||
// Order is not preserved when removing objects.
|
||||
template<class T, int max_size>
|
||||
class InlineFastList {
|
||||
public:
|
||||
InlineFastList() : count_(0) {}
|
||||
~InlineFastList() {}
|
||||
|
||||
T& operator [](int index) { return data_[index]; }
|
||||
const T& operator [](int index) const { return data_[index]; }
|
||||
int size() const { return count_; }
|
||||
|
||||
void Add(T t) {
|
||||
data_[count_++] = t;
|
||||
}
|
||||
|
||||
void RemoveAt(int index) {
|
||||
data_[index] = data_[count_ - 1];
|
||||
count_--;
|
||||
}
|
||||
|
||||
void Remove(T t) { // Requires operator==
|
||||
for (int i = 0; i < count_; i++) {
|
||||
if (data_[i] == t) {
|
||||
RemoveAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
T data_[max_size];
|
||||
int count_;
|
||||
};
|
@ -1,19 +0,0 @@
|
||||
#include "base/fastlist.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
/*
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(fastlist, AddRemove) {
|
||||
InlineFastList<int, 8> list;
|
||||
list.Add(8);
|
||||
list.Remove(7);
|
||||
EXPECT_EQ(1, list.size());
|
||||
list.Remove(8);
|
||||
EXPECT_EQ(0, list.size());
|
||||
list.Add(1);
|
||||
list.Add(2);
|
||||
list.Add(3);
|
||||
EXPECT_EQ(3, list.size());
|
||||
}
|
||||
*/
|
@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Trivial implementation of boost::scoped_ptr, in a way that I prefer.
|
||||
|
||||
template<class T>
|
||||
class scoped_ptr {
|
||||
public:
|
||||
scoped_ptr() : ptr_(0) {}
|
||||
scoped_ptr(T *p) : ptr_(p) {}
|
||||
~scoped_ptr() {
|
||||
delete ptr_;
|
||||
}
|
||||
void reset(T *p) {
|
||||
delete ptr_;
|
||||
ptr_ = p;
|
||||
}
|
||||
T *release() {
|
||||
T *p = ptr_;
|
||||
ptr_ = 0;
|
||||
return p;
|
||||
}
|
||||
T *operator->() { return ptr_; }
|
||||
const T *operator->() const { return ptr_; }
|
||||
const T *get() const { return ptr_; }
|
||||
T *get() { return ptr_; }
|
||||
private:
|
||||
scoped_ptr(const scoped_ptr<T> &other);
|
||||
void operator=(const scoped_ptr<T> &other);
|
||||
T *ptr_;
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Statistics collection. Not very developed.
|
||||
|
||||
#define STATS_ENABLE
|
||||
|
||||
#ifdef STATS_ENABLE
|
||||
|
||||
void IncrementStat(const char *name);
|
||||
|
||||
#define INCSTAT(name) IncrementStat(name);
|
||||
|
||||
#else
|
||||
|
||||
#define INCSTAT(name)
|
||||
|
||||
#endif
|
||||
|
@ -1,52 +0,0 @@
|
||||
Use of this software is granted under one of the following two licenses,
|
||||
to be chosen freely by the user.
|
||||
|
||||
1. Boost Software License - Version 1.0 - August 17th, 2003
|
||||
===============================================================================
|
||||
|
||||
Copyright (c) 2006, 2007 Marcin Kalicinski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
2. The MIT License
|
||||
===============================================================================
|
||||
|
||||
Copyright (c) 2006, 2007 Marcin Kalicinski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -1,174 +0,0 @@
|
||||
#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||
#define RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_iterators.hpp This file contains rapidxml iterators
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
//! Iterator of child nodes of xml_node
|
||||
template<class Ch>
|
||||
class node_iterator
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef typename xml_node<Ch> value_type;
|
||||
typedef typename xml_node<Ch> &reference;
|
||||
typedef typename xml_node<Ch> *pointer;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
node_iterator()
|
||||
: m_node(0)
|
||||
{
|
||||
}
|
||||
|
||||
node_iterator(xml_node<Ch> *node)
|
||||
: m_node(node->first_node())
|
||||
{
|
||||
}
|
||||
|
||||
reference operator *() const
|
||||
{
|
||||
assert(m_node);
|
||||
return *m_node;
|
||||
}
|
||||
|
||||
pointer operator->() const
|
||||
{
|
||||
assert(m_node);
|
||||
return m_node;
|
||||
}
|
||||
|
||||
node_iterator& operator++()
|
||||
{
|
||||
assert(m_node);
|
||||
m_node = m_node->next_sibling();
|
||||
return *this;
|
||||
}
|
||||
|
||||
node_iterator operator++(int)
|
||||
{
|
||||
node_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
node_iterator& operator--()
|
||||
{
|
||||
assert(m_node && m_node->previous_sibling());
|
||||
m_node = m_node->previous_sibling();
|
||||
return *this;
|
||||
}
|
||||
|
||||
node_iterator operator--(int)
|
||||
{
|
||||
node_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator ==(const node_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_node == rhs.m_node;
|
||||
}
|
||||
|
||||
bool operator !=(const node_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_node != rhs.m_node;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
xml_node<Ch> *m_node;
|
||||
|
||||
};
|
||||
|
||||
//! Iterator of child attributes of xml_node
|
||||
template<class Ch>
|
||||
class attribute_iterator
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef typename xml_attribute<Ch> value_type;
|
||||
typedef typename xml_attribute<Ch> &reference;
|
||||
typedef typename xml_attribute<Ch> *pointer;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
attribute_iterator()
|
||||
: m_attribute(0)
|
||||
{
|
||||
}
|
||||
|
||||
attribute_iterator(xml_node<Ch> *node)
|
||||
: m_attribute(node->first_attribute())
|
||||
{
|
||||
}
|
||||
|
||||
reference operator *() const
|
||||
{
|
||||
assert(m_attribute);
|
||||
return *m_attribute;
|
||||
}
|
||||
|
||||
pointer operator->() const
|
||||
{
|
||||
assert(m_attribute);
|
||||
return m_attribute;
|
||||
}
|
||||
|
||||
attribute_iterator& operator++()
|
||||
{
|
||||
assert(m_attribute);
|
||||
m_attribute = m_attribute->next_attribute();
|
||||
return *this;
|
||||
}
|
||||
|
||||
attribute_iterator operator++(int)
|
||||
{
|
||||
attribute_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
attribute_iterator& operator--()
|
||||
{
|
||||
assert(m_attribute && m_attribute->previous_attribute());
|
||||
m_attribute = m_attribute->previous_attribute();
|
||||
return *this;
|
||||
}
|
||||
|
||||
attribute_iterator operator--(int)
|
||||
{
|
||||
attribute_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator ==(const attribute_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_attribute == rhs.m_attribute;
|
||||
}
|
||||
|
||||
bool operator !=(const attribute_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_attribute != rhs.m_attribute;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
xml_attribute<Ch> *m_attribute;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,421 +0,0 @@
|
||||
#ifndef RAPIDXML_PRINT_HPP_INCLUDED
|
||||
#define RAPIDXML_PRINT_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_print.hpp This file contains rapidxml printer implementation
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
|
||||
// Only include streams if not disabled
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
#include <ostream>
|
||||
#include <iterator>
|
||||
#endif
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Printing flags
|
||||
|
||||
const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Internal
|
||||
|
||||
//! \cond internal
|
||||
namespace internal
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Internal character operations
|
||||
|
||||
// Copy characters from given range to given output iterator
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
*out++ = *begin++;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Copy characters from given range to given output iterator and expand
|
||||
// characters into references (< > ' " &)
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
{
|
||||
if (*begin == noexpand)
|
||||
{
|
||||
*out++ = *begin; // No expansion, copy character
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (*begin)
|
||||
{
|
||||
case Ch('<'):
|
||||
*out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('>'):
|
||||
*out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('\''):
|
||||
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('"'):
|
||||
*out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('&'):
|
||||
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
|
||||
break;
|
||||
default:
|
||||
*out++ = *begin; // No expansion, copy character
|
||||
}
|
||||
}
|
||||
++begin; // Step to next character
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Fill given output iterator with repetitions of the same character
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt fill_chars(OutIt out, int n, Ch ch)
|
||||
{
|
||||
for (int i = 0; i < n; ++i)
|
||||
*out++ = ch;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Find character
|
||||
template<class Ch, Ch ch>
|
||||
inline bool find_char(const Ch *begin, const Ch *end)
|
||||
{
|
||||
while (begin != end)
|
||||
if (*begin++ == ch)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Internal printing operations
|
||||
|
||||
// Print node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
// Print proper node type
|
||||
switch (node->type())
|
||||
{
|
||||
|
||||
// Document
|
||||
case node_document:
|
||||
out = print_children(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Element
|
||||
case node_element:
|
||||
out = print_element_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Data
|
||||
case node_data:
|
||||
out = print_data_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// CDATA
|
||||
case node_cdata:
|
||||
out = print_cdata_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Declaration
|
||||
case node_declaration:
|
||||
out = print_declaration_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Comment
|
||||
case node_comment:
|
||||
out = print_comment_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Doctype
|
||||
case node_doctype:
|
||||
out = print_doctype_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Pi
|
||||
case node_pi:
|
||||
out = print_pi_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Unknown
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
// If indenting not disabled, add line break after node
|
||||
if (!(flags & print_no_indenting))
|
||||
*out = Ch('\n'), ++out;
|
||||
|
||||
// Return modified iterator
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print children of the node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
|
||||
out = print_node(out, child, flags, indent);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print attributes of the node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
|
||||
{
|
||||
for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
|
||||
{
|
||||
if (attribute->name() && attribute->value())
|
||||
{
|
||||
// Print attribute name
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
|
||||
*out = Ch('='), ++out;
|
||||
// Print attribute value using appropriate quote type
|
||||
if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
|
||||
{
|
||||
*out = Ch('\''), ++out;
|
||||
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
|
||||
*out = Ch('\''), ++out;
|
||||
}
|
||||
else
|
||||
{
|
||||
*out = Ch('"'), ++out;
|
||||
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
|
||||
*out = Ch('"'), ++out;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print data node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_data);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print data node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_cdata);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'); ++out;
|
||||
*out = Ch('!'); ++out;
|
||||
*out = Ch('['); ++out;
|
||||
*out = Ch('C'); ++out;
|
||||
*out = Ch('D'); ++out;
|
||||
*out = Ch('A'); ++out;
|
||||
*out = Ch('T'); ++out;
|
||||
*out = Ch('A'); ++out;
|
||||
*out = Ch('['); ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch(']'); ++out;
|
||||
*out = Ch(']'); ++out;
|
||||
*out = Ch('>'); ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print element node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_element);
|
||||
|
||||
// Print element name and attributes, if any
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
out = print_attributes(out, node, flags);
|
||||
|
||||
// If node is childless
|
||||
if (node->value_size() == 0 && !node->first_node())
|
||||
{
|
||||
// Print childless node tag ending
|
||||
*out = Ch('/'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print normal node tag ending
|
||||
*out = Ch('>'), ++out;
|
||||
|
||||
// Test if node contains a single data node only (and no other nodes)
|
||||
xml_node<Ch> *child = node->first_node();
|
||||
if (!child)
|
||||
{
|
||||
// If node has no children, only print its value without indenting
|
||||
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||
}
|
||||
else if (child->next_sibling() == 0 && child->type() == node_data)
|
||||
{
|
||||
// If node has a sole data child, only print its value without indenting
|
||||
out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print all children with full indenting
|
||||
if (!(flags & print_no_indenting))
|
||||
*out = Ch('\n'), ++out;
|
||||
out = print_children(out, node, flags, indent + 1);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
}
|
||||
|
||||
// Print node end
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('/'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
*out = Ch('>'), ++out;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print declaration node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
// Print declaration start
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('x'), ++out;
|
||||
*out = Ch('m'), ++out;
|
||||
*out = Ch('l'), ++out;
|
||||
|
||||
// Print attributes
|
||||
out = print_attributes(out, node, flags);
|
||||
|
||||
// Print declaration end
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print comment node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_comment);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('!'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print doctype node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_doctype);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('!'), ++out;
|
||||
*out = Ch('D'), ++out;
|
||||
*out = Ch('O'), ++out;
|
||||
*out = Ch('C'), ++out;
|
||||
*out = Ch('T'), ++out;
|
||||
*out = Ch('Y'), ++out;
|
||||
*out = Ch('P'), ++out;
|
||||
*out = Ch('E'), ++out;
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print pi node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_pi);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('?'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
//! \endcond
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Printing
|
||||
|
||||
//! Prints XML to given output iterator.
|
||||
//! \param out Output iterator to print to.
|
||||
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||
//! \param flags Flags controlling how XML is printed.
|
||||
//! \return Output iterator pointing to position immediately after last character of printed text.
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
|
||||
{
|
||||
return internal::print_node(out, &node, flags, 0);
|
||||
}
|
||||
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
|
||||
//! Prints XML to given output stream.
|
||||
//! \param out Output stream to print to.
|
||||
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||
//! \param flags Flags controlling how XML is printed.
|
||||
//! \return Output stream.
|
||||
template<class Ch>
|
||||
inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
|
||||
{
|
||||
print(std::ostream_iterator<Ch>(out), node, flags);
|
||||
return out;
|
||||
}
|
||||
|
||||
//! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
|
||||
//! \param out Output stream to print to.
|
||||
//! \param node Node to be printed.
|
||||
//! \return Output stream.
|
||||
template<class Ch>
|
||||
inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
|
||||
{
|
||||
return print(out, node);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,122 +0,0 @@
|
||||
#ifndef RAPIDXML_UTILS_HPP_INCLUDED
|
||||
#define RAPIDXML_UTILS_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful
|
||||
//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective.
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
//! Represents data loaded from a file
|
||||
template<class Ch = char>
|
||||
class file
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//! Loads file into the memory. Data will be automatically destroyed by the destructor.
|
||||
//! \param filename Filename to load.
|
||||
file(const char *filename)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// Open stream
|
||||
basic_ifstream<Ch> stream(filename, ios::binary);
|
||||
if (!stream)
|
||||
throw runtime_error(string("cannot open file ") + filename);
|
||||
stream.unsetf(ios::skipws);
|
||||
|
||||
// Determine stream size
|
||||
stream.seekg(0, ios::end);
|
||||
size_t size = stream.tellg();
|
||||
stream.seekg(0);
|
||||
|
||||
// Load data and add terminating 0
|
||||
m_data.resize(size + 1);
|
||||
stream.read(&m_data.front(), static_cast<streamsize>(size));
|
||||
m_data[size] = 0;
|
||||
}
|
||||
|
||||
//! Loads file into the memory. Data will be automatically destroyed by the destructor
|
||||
//! \param stream Stream to load from
|
||||
file(std::basic_istream<Ch> &stream)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// Load data and add terminating 0
|
||||
stream.unsetf(ios::skipws);
|
||||
m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>());
|
||||
if (stream.fail() || stream.bad())
|
||||
throw runtime_error("error reading stream");
|
||||
m_data.push_back(0);
|
||||
}
|
||||
|
||||
//! Gets file data.
|
||||
//! \return Pointer to data of file.
|
||||
Ch *data()
|
||||
{
|
||||
return &m_data.front();
|
||||
}
|
||||
|
||||
//! Gets file data.
|
||||
//! \return Pointer to data of file.
|
||||
const Ch *data() const
|
||||
{
|
||||
return &m_data.front();
|
||||
}
|
||||
|
||||
//! Gets file data size.
|
||||
//! \return Size of file data, in characters.
|
||||
std::size_t size() const
|
||||
{
|
||||
return m_data.size();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector<Ch> m_data; // File data
|
||||
|
||||
};
|
||||
|
||||
//! Counts children of node. Time complexity is O(n).
|
||||
//! \return Number of children of node
|
||||
template<class Ch>
|
||||
inline std::size_t count_children(xml_node<Ch> *node)
|
||||
{
|
||||
xml_node<Ch> *child = node->first_node();
|
||||
std::size_t count = 0;
|
||||
while (child)
|
||||
{
|
||||
++count;
|
||||
child = child->next_sibling();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//! Counts attributes of node. Time complexity is O(n).
|
||||
//! \return Number of attributes of node
|
||||
template<class Ch>
|
||||
inline std::size_t count_attributes(xml_node<Ch> *node)
|
||||
{
|
||||
xml_attribute<Ch> *attr = node->first_attribute();
|
||||
std::size_t count = 0;
|
||||
while (attr)
|
||||
{
|
||||
++count;
|
||||
attr = attr->next_attribute();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,7 +0,0 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
#if(UNIX)
|
||||
add_definitions(-fPIC)
|
||||
#endif(UNIX)
|
||||
|
||||
add_library(stb_image stb_image.c)
|
File diff suppressed because it is too large
Load Diff
@ -1,262 +0,0 @@
|
||||
#pragma once
|
||||
//// begin header file ////////////////////////////////////////////////////
|
||||
//
|
||||
// Limitations:
|
||||
// - no jpeg progressive support
|
||||
// - non-HDR formats support 8-bit samples only (jpeg, png)
|
||||
// - no delayed line count (jpeg) -- IJG doesn't support either
|
||||
// - no 1-bit BMP
|
||||
// - GIF always returns *comp=4
|
||||
//
|
||||
// Basic usage (see HDR discussion below):
|
||||
// int x,y,n;
|
||||
// unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
|
||||
// // ... process data if not NULL ...
|
||||
// // ... x = width, y = height, n = # 8-bit components per pixel ...
|
||||
// // ... replace '0' with '1'..'4' to force that many components per pixel
|
||||
// // ... but 'n' will always be the number that it would have been if you said 0
|
||||
// stbi_image_free(data)
|
||||
//
|
||||
// Standard parameters:
|
||||
// int *x -- outputs image width in pixels
|
||||
// int *y -- outputs image height in pixels
|
||||
// int *comp -- outputs # of image components in image file
|
||||
// int req_comp -- if non-zero, # of image components requested in result
|
||||
//
|
||||
// The return value from an image loader is an 'unsigned char *' which points
|
||||
// to the pixel data. The pixel data consists of *y scanlines of *x pixels,
|
||||
// with each pixel consisting of N interleaved 8-bit components; the first
|
||||
// pixel pointed to is top-left-most in the image. There is no padding between
|
||||
// image scanlines or between pixels, regardless of format. The number of
|
||||
// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise.
|
||||
// If req_comp is non-zero, *comp has the number of components that _would_
|
||||
// have been output otherwise. E.g. if you set req_comp to 4, you will always
|
||||
// get RGBA output, but you can check *comp to easily see if it's opaque.
|
||||
//
|
||||
// An output image with N components has the following components interleaved
|
||||
// in this order in each pixel:
|
||||
//
|
||||
// N=#comp components
|
||||
// 1 grey
|
||||
// 2 grey, alpha
|
||||
// 3 red, green, blue
|
||||
// 4 red, green, blue, alpha
|
||||
//
|
||||
// If image loading fails for any reason, the return value will be NULL,
|
||||
// and *x, *y, *comp will be unchanged. The function stbi_failure_reason()
|
||||
// can be queried for an extremely brief, end-user unfriendly explanation
|
||||
// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid
|
||||
// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
|
||||
// more user-friendly ones.
|
||||
//
|
||||
// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
|
||||
//
|
||||
// ===========================================================================
|
||||
//
|
||||
// iPhone PNG support:
|
||||
//
|
||||
// By default we convert iphone-formatted PNGs back to RGB; nominally they
|
||||
// would silently load as BGR, except the existing code should have just
|
||||
// failed on such iPhone PNGs. But you can disable this conversion by
|
||||
// by calling stbi_convert_iphone_png_to_rgb(0), in which case
|
||||
// you will always just get the native iphone "format" through.
|
||||
//
|
||||
// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
|
||||
// pixel to remove any premultiplied alpha *only* if the image file explicitly
|
||||
// says there's premultiplied data (currently only happens in iPhone images,
|
||||
// and only if iPhone convert-to-rgb processing is on).
|
||||
//
|
||||
// ===========================================================================
|
||||
//
|
||||
// HDR image support (disable by defining STBI_NO_HDR)
|
||||
//
|
||||
// stb_image now supports loading HDR images in general, and currently
|
||||
// the Radiance .HDR file format, although the support is provided
|
||||
// generically. You can still load any file through the existing interface;
|
||||
// if you attempt to load an HDR file, it will be automatically remapped to
|
||||
// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
|
||||
// both of these constants can be reconfigured through this interface:
|
||||
//
|
||||
// stbi_hdr_to_ldr_gamma(2.2f);
|
||||
// stbi_hdr_to_ldr_scale(1.0f);
|
||||
//
|
||||
// (note, do not use _inverse_ constants; stbi_image will invert them
|
||||
// appropriately).
|
||||
//
|
||||
// Additionally, there is a new, parallel interface for loading files as
|
||||
// (linear) floats to preserve the full dynamic range:
|
||||
//
|
||||
// float *data = stbi_loadf(filename, &x, &y, &n, 0);
|
||||
//
|
||||
// If you load LDR images through this interface, those images will
|
||||
// be promoted to floating point values, run through the inverse of
|
||||
// constants corresponding to the above:
|
||||
//
|
||||
// stbi_ldr_to_hdr_scale(1.0f);
|
||||
// stbi_ldr_to_hdr_gamma(2.2f);
|
||||
//
|
||||
// Finally, given a filename (or an open file or memory block--see header
|
||||
// file for details) containing image data, you can query for the "most
|
||||
// appropriate" interface to use (that is, whether the image is HDR or
|
||||
// not), using:
|
||||
//
|
||||
// stbi_is_hdr(char *filename);
|
||||
//
|
||||
// ===========================================================================
|
||||
//
|
||||
// I/O callbacks
|
||||
//
|
||||
// I/O callbacks allow you to read from arbitrary sources, like packaged
|
||||
// files or some other source. Data read from callbacks are processed
|
||||
// through a small internal buffer (currently 128 bytes) to try to reduce
|
||||
// overhead.
|
||||
//
|
||||
// The three functions you must define are "read" (reads some bytes of data),
|
||||
// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
|
||||
|
||||
|
||||
#ifndef STBI_NO_STDIO
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 0x1400
|
||||
#define _CRT_SECURE_NO_WARNINGS // suppress bogus warnings about fopen()
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#define STBI_VERSION 1
|
||||
|
||||
enum
|
||||
{
|
||||
STBI_default = 0, // only used for req_comp
|
||||
|
||||
STBI_grey = 1,
|
||||
STBI_grey_alpha = 2,
|
||||
STBI_rgb = 3,
|
||||
STBI_rgb_alpha = 4
|
||||
};
|
||||
|
||||
typedef unsigned char stbi_uc;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PRIMARY API - works on images of any type
|
||||
//
|
||||
|
||||
//
|
||||
// load image by filename, open file, or memory buffer
|
||||
//
|
||||
|
||||
extern stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
|
||||
|
||||
#ifndef STBI_NO_STDIO
|
||||
extern stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp);
|
||||
extern stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
|
||||
// for stbi_load_from_file, file pointer is left pointing immediately after image
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read
|
||||
void (*skip) (void *user,unsigned n); // skip the next 'n' bytes
|
||||
int (*eof) (void *user); // returns nonzero if we are at end of file/data
|
||||
} stbi_io_callbacks;
|
||||
|
||||
extern stbi_uc *stbi_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);
|
||||
|
||||
#ifndef STBI_NO_HDR
|
||||
extern float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
|
||||
|
||||
#ifndef STBI_NO_STDIO
|
||||
extern float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp);
|
||||
extern float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
|
||||
#endif
|
||||
|
||||
extern float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);
|
||||
|
||||
extern void stbi_hdr_to_ldr_gamma(float gamma);
|
||||
extern void stbi_hdr_to_ldr_scale(float scale);
|
||||
|
||||
extern void stbi_ldr_to_hdr_gamma(float gamma);
|
||||
extern void stbi_ldr_to_hdr_scale(float scale);
|
||||
#endif // STBI_NO_HDR
|
||||
|
||||
// stbi_is_hdr is always defined
|
||||
extern int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
|
||||
extern int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
|
||||
#ifndef STBI_NO_STDIO
|
||||
extern int stbi_is_hdr (char const *filename);
|
||||
extern int stbi_is_hdr_from_file(FILE *f);
|
||||
#endif // STBI_NO_STDIO
|
||||
|
||||
|
||||
// get a VERY brief reason for failure
|
||||
// NOT THREADSAFE
|
||||
extern const char *stbi_failure_reason (void);
|
||||
|
||||
// free the loaded image -- this is just free()
|
||||
extern void stbi_image_free (void *retval_from_stbi_load);
|
||||
|
||||
// get image dimensions & components without fully decoding
|
||||
extern int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
|
||||
extern int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
|
||||
|
||||
#ifndef STBI_NO_STDIO
|
||||
extern int stbi_info (char const *filename, int *x, int *y, int *comp);
|
||||
extern int stbi_info_from_file (FILE *f, int *x, int *y, int *comp);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// for image formats that explicitly notate that they have premultiplied alpha,
|
||||
// we just return the colors as stored in the file. set this flag to force
|
||||
// unpremultiplication. results are undefined if the unpremultiply overflow.
|
||||
extern void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
|
||||
|
||||
// indicate whether we should process iphone images back to canonical format,
|
||||
// or just pass them through "as-is"
|
||||
extern void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
|
||||
|
||||
|
||||
// ZLIB client - used by PNG, available for other purposes
|
||||
|
||||
extern char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
|
||||
extern char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
|
||||
extern int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
|
||||
|
||||
extern char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
|
||||
extern int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
|
||||
|
||||
|
||||
// define faster low-level operations (typically SIMD support)
|
||||
#ifdef STBI_SIMD
|
||||
typedef void (*stbi_idct_8x8)(stbi_uc *out, int out_stride, short data[64], unsigned short *dequantize);
|
||||
// compute an integer IDCT on "input"
|
||||
// input[x] = data[x] * dequantize[x]
|
||||
// write results to 'out': 64 samples, each run of 8 spaced by 'out_stride'
|
||||
// CLAMP results to 0..255
|
||||
typedef void (*stbi_YCbCr_to_RGB_run)(stbi_uc *output, stbi_uc const *y, stbi_uc const *cb, stbi_uc const *cr, int count, int step);
|
||||
// compute a conversion from YCbCr to RGB
|
||||
// 'count' pixels
|
||||
// write pixels to 'output'; each pixel is 'step' bytes (either 3 or 4; if 4, write '255' as 4th), order R,G,B
|
||||
// y: Y input channel
|
||||
// cb: Cb input channel; scale/biased to be 0..255
|
||||
// cr: Cr input channel; scale/biased to be 0..255
|
||||
|
||||
extern void stbi_install_idct(stbi_idct_8x8 func);
|
||||
extern void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func);
|
||||
#endif // STBI_SIMD
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
//
|
||||
//// end header file /////////////////////////////////////////////////////
|
@ -1,2 +0,0 @@
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "ext/stb_image_write/stb_image_writer.h"
|
@ -1,511 +0,0 @@
|
||||
/* stbiw-0.92 - public domain - http://nothings.org/stb/stb_image_write.h
|
||||
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
|
||||
Before including,
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
in the file that you want to have the implementation.
|
||||
|
||||
|
||||
ABOUT:
|
||||
|
||||
This header file is a library for writing images to C stdio. It could be
|
||||
adapted to write to memory or a general streaming interface; let me know.
|
||||
|
||||
The PNG output is not optimal; it is 20-50% larger than the file
|
||||
written by a decent optimizing implementation. This library is designed
|
||||
for source code compactness and simplicitly, not optimal image file size
|
||||
or run-time performance.
|
||||
|
||||
USAGE:
|
||||
|
||||
There are three functions, one for each image file format:
|
||||
|
||||
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
||||
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
||||
|
||||
Each function returns 0 on failure and non-0 on success.
|
||||
|
||||
The functions create an image file defined by the parameters. The image
|
||||
is a rectangle of pixels stored from left-to-right, top-to-bottom.
|
||||
Each pixel contains 'comp' channels of data stored interleaved with 8-bits
|
||||
per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
|
||||
monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
|
||||
The *data pointer points to the first byte of the top-left-most pixel.
|
||||
For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
|
||||
a row of pixels to the first byte of the next row of pixels.
|
||||
|
||||
PNG creates output files with the same number of components as the input.
|
||||
The BMP and TGA formats expand Y to RGB in the file format. BMP does not
|
||||
output alpha.
|
||||
|
||||
PNG supports writing rectangles of data even when the bytes storing rows of
|
||||
data are not consecutive in memory (e.g. sub-rectangles of a larger image),
|
||||
by supplying the stride between the beginning of adjacent rows. The other
|
||||
formats do not. (Thus you cannot write a native-format BMP through the BMP
|
||||
writer, both because it is in BGR order and because it may have padding
|
||||
at the end of the line.)
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_STB_IMAGE_WRITE_H
|
||||
#define INCLUDE_STB_IMAGE_WRITE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||
extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
||||
extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif//INCLUDE_STB_IMAGE_WRITE_H
|
||||
|
||||
#ifdef STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
typedef unsigned int stbiw_uint32;
|
||||
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
|
||||
|
||||
static void writefv(FILE *f, const char *fmt, va_list v)
|
||||
{
|
||||
while (*fmt) {
|
||||
switch (*fmt++) {
|
||||
case ' ': break;
|
||||
case '1': { unsigned char x = (unsigned char) va_arg(v, int); fputc(x,f); break; }
|
||||
case '2': { int x = va_arg(v,int); unsigned char b[2];
|
||||
b[0] = (unsigned char) x; b[1] = (unsigned char) (x>>8);
|
||||
fwrite(b,2,1,f); break; }
|
||||
case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4];
|
||||
b[0]=(unsigned char)x; b[1]=(unsigned char)(x>>8);
|
||||
b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
|
||||
fwrite(b,4,1,f); break; }
|
||||
default:
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c)
|
||||
{
|
||||
unsigned char arr[3];
|
||||
arr[0] = a, arr[1] = b, arr[2] = c;
|
||||
fwrite(arr, 3, 1, f);
|
||||
}
|
||||
|
||||
static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad)
|
||||
{
|
||||
unsigned char bg[3] = { 255, 0, 255}, px[3];
|
||||
stbiw_uint32 zero = 0;
|
||||
int i,j,k, j_end;
|
||||
|
||||
if (y <= 0)
|
||||
return;
|
||||
|
||||
if (vdir < 0)
|
||||
j_end = -1, j = y-1;
|
||||
else
|
||||
j_end = y, j = 0;
|
||||
|
||||
for (; j != j_end; j += vdir) {
|
||||
for (i=0; i < x; ++i) {
|
||||
unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
|
||||
if (write_alpha < 0)
|
||||
fwrite(&d[comp-1], 1, 1, f);
|
||||
switch (comp) {
|
||||
case 1:
|
||||
case 2: write3(f, d[0],d[0],d[0]);
|
||||
break;
|
||||
case 4:
|
||||
if (!write_alpha) {
|
||||
// composite against pink background
|
||||
for (k=0; k < 3; ++k)
|
||||
px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255;
|
||||
write3(f, px[1-rgb_dir],px[1],px[1+rgb_dir]);
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case 3:
|
||||
write3(f, d[1-rgb_dir],d[1],d[1+rgb_dir]);
|
||||
break;
|
||||
}
|
||||
if (write_alpha > 0)
|
||||
fwrite(&d[comp-1], 1, 1, f);
|
||||
}
|
||||
fwrite(&zero,scanline_pad,1,f);
|
||||
}
|
||||
}
|
||||
|
||||
static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, void *data, int alpha, int pad, const char *fmt, ...)
|
||||
{
|
||||
FILE *f;
|
||||
if (y < 0 || x < 0) return 0;
|
||||
f = fopen(filename, "wb");
|
||||
if (f) {
|
||||
va_list v;
|
||||
va_start(v, fmt);
|
||||
writefv(f, fmt, v);
|
||||
va_end(v);
|
||||
write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad);
|
||||
fclose(f);
|
||||
}
|
||||
return f != NULL;
|
||||
}
|
||||
|
||||
int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
|
||||
{
|
||||
int pad = (-x*3) & 3;
|
||||
return outfile(filename,-1,-1,x,y,comp,(void *) data,0,pad,
|
||||
"11 4 22 4" "4 44 22 444444",
|
||||
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
|
||||
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
|
||||
}
|
||||
|
||||
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
|
||||
{
|
||||
int has_alpha = !(comp & 1);
|
||||
return outfile(filename, -1,-1, x, y, comp, (void *) data, has_alpha, 0,
|
||||
"111 221 2222 11", 0,0,2, 0,0,0, 0,0,x,y, 24+8*has_alpha, 8*has_alpha);
|
||||
}
|
||||
|
||||
// stretchy buffer; stbi__sbpush() == vector<>::push_back() -- stbi__sbcount() == vector<>::size()
|
||||
#define stbi__sbraw(a) ((int *) (a) - 2)
|
||||
#define stbi__sbm(a) stbi__sbraw(a)[0]
|
||||
#define stbi__sbn(a) stbi__sbraw(a)[1]
|
||||
|
||||
#define stbi__sbneedgrow(a,n) ((a)==0 || stbi__sbn(a)+n >= stbi__sbm(a))
|
||||
#define stbi__sbmaybegrow(a,n) (stbi__sbneedgrow(a,(n)) ? stbi__sbgrow(a,n) : 0)
|
||||
#define stbi__sbgrow(a,n) stbi__sbgrowf((void **) &(a), (n), sizeof(*(a)))
|
||||
|
||||
#define stbi__sbpush(a, v) (stbi__sbmaybegrow(a,1), (a)[stbi__sbn(a)++] = (v))
|
||||
#define stbi__sbcount(a) ((a) ? stbi__sbn(a) : 0)
|
||||
#define stbi__sbfree(a) ((a) ? free(stbi__sbraw(a)),0 : 0)
|
||||
|
||||
static void *stbi__sbgrowf(void **arr, int increment, int itemsize)
|
||||
{
|
||||
int m = *arr ? 2*stbi__sbm(*arr)+increment : increment+1;
|
||||
void *p = realloc(*arr ? stbi__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
|
||||
assert(p);
|
||||
if (p) {
|
||||
if (!*arr) ((int *) p)[1] = 0;
|
||||
*arr = (void *) ((int *) p + 2);
|
||||
stbi__sbm(*arr) = m;
|
||||
}
|
||||
return *arr;
|
||||
}
|
||||
|
||||
static unsigned char *stbi__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
|
||||
{
|
||||
while (*bitcount >= 8) {
|
||||
stbi__sbpush(data, (unsigned char) *bitbuffer);
|
||||
*bitbuffer >>= 8;
|
||||
*bitcount -= 8;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static int stbi__zlib_bitrev(int code, int codebits)
|
||||
{
|
||||
int res=0;
|
||||
while (codebits--) {
|
||||
res = (res << 1) | (code & 1);
|
||||
code >>= 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static unsigned int stbi__zlib_countm(unsigned char *a, unsigned char *b, int limit)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < limit && i < 258; ++i)
|
||||
if (a[i] != b[i]) break;
|
||||
return i;
|
||||
}
|
||||
|
||||
static unsigned int stbi__zhash(unsigned char *data)
|
||||
{
|
||||
stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
|
||||
hash ^= hash << 3;
|
||||
hash += hash >> 5;
|
||||
hash ^= hash << 4;
|
||||
hash += hash >> 17;
|
||||
hash ^= hash << 25;
|
||||
hash += hash >> 6;
|
||||
return hash;
|
||||
}
|
||||
|
||||
#define stbi__zlib_flush() (out = stbi__zlib_flushf(out, &bitbuf, &bitcount))
|
||||
#define stbi__zlib_add(code,codebits) \
|
||||
(bitbuf |= (code) << bitcount, bitcount += (codebits), stbi__zlib_flush())
|
||||
#define stbi__zlib_huffa(b,c) stbi__zlib_add(stbi__zlib_bitrev(b,c),c)
|
||||
// default huffman tables
|
||||
#define stbi__zlib_huff1(n) stbi__zlib_huffa(0x30 + (n), 8)
|
||||
#define stbi__zlib_huff2(n) stbi__zlib_huffa(0x190 + (n)-144, 9)
|
||||
#define stbi__zlib_huff3(n) stbi__zlib_huffa(0 + (n)-256,7)
|
||||
#define stbi__zlib_huff4(n) stbi__zlib_huffa(0xc0 + (n)-280,8)
|
||||
#define stbi__zlib_huff(n) ((n) <= 143 ? stbi__zlib_huff1(n) : (n) <= 255 ? stbi__zlib_huff2(n) : (n) <= 279 ? stbi__zlib_huff3(n) : stbi__zlib_huff4(n))
|
||||
#define stbi__zlib_huffb(n) ((n) <= 143 ? stbi__zlib_huff1(n) : stbi__zlib_huff2(n))
|
||||
|
||||
#define stbi__ZHASH 16384
|
||||
|
||||
unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
|
||||
{
|
||||
static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
|
||||
static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
|
||||
static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
|
||||
static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };
|
||||
unsigned int bitbuf=0;
|
||||
int i,j, bitcount=0;
|
||||
unsigned char *out = NULL;
|
||||
unsigned char **hash_table[stbi__ZHASH]; // 64KB on the stack!
|
||||
if (quality < 5) quality = 5;
|
||||
|
||||
stbi__sbpush(out, 0x78); // DEFLATE 32K window
|
||||
stbi__sbpush(out, 0x5e); // FLEVEL = 1
|
||||
stbi__zlib_add(1,1); // BFINAL = 1
|
||||
stbi__zlib_add(1,2); // BTYPE = 1 -- fixed huffman
|
||||
|
||||
for (i=0; i < stbi__ZHASH; ++i)
|
||||
hash_table[i] = NULL;
|
||||
|
||||
i=0;
|
||||
while (i < data_len-3) {
|
||||
// hash next 3 bytes of data to be compressed
|
||||
int h = stbi__zhash(data+i)&(stbi__ZHASH-1), best=3;
|
||||
unsigned char *bestloc = 0;
|
||||
unsigned char **hlist = hash_table[h];
|
||||
int n = stbi__sbcount(hlist);
|
||||
for (j=0; j < n; ++j) {
|
||||
if (hlist[j]-data > i-32768) { // if entry lies within window
|
||||
int d = stbi__zlib_countm(hlist[j], data+i, data_len-i);
|
||||
if (d >= best) best=d,bestloc=hlist[j];
|
||||
}
|
||||
}
|
||||
// when hash table entry is too long, delete half the entries
|
||||
if (hash_table[h] && stbi__sbn(hash_table[h]) == 2*quality) {
|
||||
memcpy(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
|
||||
stbi__sbn(hash_table[h]) = quality;
|
||||
}
|
||||
stbi__sbpush(hash_table[h],data+i);
|
||||
|
||||
if (bestloc) {
|
||||
// "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
|
||||
h = stbi__zhash(data+i+1)&(stbi__ZHASH-1);
|
||||
hlist = hash_table[h];
|
||||
n = stbi__sbcount(hlist);
|
||||
for (j=0; j < n; ++j) {
|
||||
if (hlist[j]-data > i-32767) {
|
||||
int e = stbi__zlib_countm(hlist[j], data+i+1, data_len-i-1);
|
||||
if (e > best) { // if next match is better, bail on current match
|
||||
bestloc = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestloc) {
|
||||
int d = data+i - bestloc; // distance back
|
||||
assert(d <= 32767 && best <= 258);
|
||||
for (j=0; best > lengthc[j+1]-1; ++j);
|
||||
stbi__zlib_huff(j+257);
|
||||
if (lengtheb[j]) stbi__zlib_add(best - lengthc[j], lengtheb[j]);
|
||||
for (j=0; d > distc[j+1]-1; ++j);
|
||||
stbi__zlib_add(stbi__zlib_bitrev(j,5),5);
|
||||
if (disteb[j]) stbi__zlib_add(d - distc[j], disteb[j]);
|
||||
i += best;
|
||||
} else {
|
||||
stbi__zlib_huffb(data[i]);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
// write out final bytes
|
||||
for (;i < data_len; ++i)
|
||||
stbi__zlib_huffb(data[i]);
|
||||
stbi__zlib_huff(256); // end of block
|
||||
// pad with 0 bits to byte boundary
|
||||
while (bitcount)
|
||||
stbi__zlib_add(0,1);
|
||||
|
||||
for (i=0; i < stbi__ZHASH; ++i)
|
||||
(void) stbi__sbfree(hash_table[i]);
|
||||
|
||||
{
|
||||
// compute adler32 on input
|
||||
unsigned int i=0, s1=1, s2=0, blocklen = data_len % 5552;
|
||||
int j=0;
|
||||
while (j < data_len) {
|
||||
for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
|
||||
s1 %= 65521, s2 %= 65521;
|
||||
j += blocklen;
|
||||
blocklen = 5552;
|
||||
}
|
||||
stbi__sbpush(out, (unsigned char) (s2 >> 8));
|
||||
stbi__sbpush(out, (unsigned char) s2);
|
||||
stbi__sbpush(out, (unsigned char) (s1 >> 8));
|
||||
stbi__sbpush(out, (unsigned char) s1);
|
||||
}
|
||||
*out_len = stbi__sbn(out);
|
||||
// make returned pointer freeable
|
||||
memmove(stbi__sbraw(out), out, *out_len);
|
||||
return (unsigned char *) stbi__sbraw(out);
|
||||
}
|
||||
|
||||
unsigned int stbi__crc32(unsigned char *buffer, int len)
|
||||
{
|
||||
static unsigned int crc_table[256];
|
||||
unsigned int crc = ~0u;
|
||||
int i,j;
|
||||
if (crc_table[1] == 0)
|
||||
for(i=0; i < 256; i++)
|
||||
for (crc_table[i]=i, j=0; j < 8; ++j)
|
||||
crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0);
|
||||
for (i=0; i < len; ++i)
|
||||
crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
#define stbi__wpng4(o,a,b,c,d) ((o)[0]=(unsigned char)(a),(o)[1]=(unsigned char)(b),(o)[2]=(unsigned char)(c),(o)[3]=(unsigned char)(d),(o)+=4)
|
||||
#define stbi__wp32(data,v) stbi__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
|
||||
#define stbi__wptag(data,s) stbi__wpng4(data, s[0],s[1],s[2],s[3])
|
||||
|
||||
static void stbi__wpcrc(unsigned char **data, int len)
|
||||
{
|
||||
unsigned int crc = stbi__crc32(*data - len - 4, len+4);
|
||||
stbi__wp32(*data, crc);
|
||||
}
|
||||
|
||||
static unsigned char stbi__paeth(int a, int b, int c)
|
||||
{
|
||||
int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
|
||||
if (pa <= pb && pa <= pc) return (unsigned char) a;
|
||||
if (pb <= pc) return (unsigned char) b;
|
||||
return (unsigned char) c;
|
||||
}
|
||||
|
||||
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
|
||||
{
|
||||
int ctype[5] = { -1, 0, 4, 2, 6 };
|
||||
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
|
||||
unsigned char *out,*o, *filt, *zlib;
|
||||
signed char *line_buffer;
|
||||
int i,j,k,p,zlen;
|
||||
|
||||
if (stride_bytes == 0)
|
||||
stride_bytes = x * n;
|
||||
|
||||
filt = (unsigned char *) malloc((x*n+1) * y); if (!filt) return 0;
|
||||
line_buffer = (signed char *) malloc(x * n); if (!line_buffer) { free(filt); return 0; }
|
||||
for (j=0; j < y; ++j) {
|
||||
static int mapping[] = { 0,1,2,3,4 };
|
||||
static int firstmap[] = { 0,1,0,5,6 };
|
||||
int *mymap = j ? mapping : firstmap;
|
||||
int best = 0, bestval = 0x7fffffff;
|
||||
for (p=0; p < 2; ++p) {
|
||||
for (k= p?best:0; k < 5; ++k) {
|
||||
int type = mymap[k],est=0;
|
||||
unsigned char *z = pixels + stride_bytes*j;
|
||||
for (i=0; i < n; ++i)
|
||||
switch (type) {
|
||||
case 0: line_buffer[i] = z[i]; break;
|
||||
case 1: line_buffer[i] = z[i]; break;
|
||||
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
|
||||
case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
|
||||
case 4: line_buffer[i] = (signed char) (z[i] - stbi__paeth(0,z[i-stride_bytes],0)); break;
|
||||
case 5: line_buffer[i] = z[i]; break;
|
||||
case 6: line_buffer[i] = z[i]; break;
|
||||
}
|
||||
for (i=n; i < x*n; ++i) {
|
||||
switch (type) {
|
||||
case 0: line_buffer[i] = z[i]; break;
|
||||
case 1: line_buffer[i] = z[i] - z[i-n]; break;
|
||||
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
|
||||
case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
|
||||
case 4: line_buffer[i] = z[i] - stbi__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
|
||||
case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
|
||||
case 6: line_buffer[i] = z[i] - stbi__paeth(z[i-n], 0,0); break;
|
||||
}
|
||||
}
|
||||
if (p) break;
|
||||
for (i=0; i < x*n; ++i)
|
||||
est += abs((signed char) line_buffer[i]);
|
||||
if (est < bestval) { bestval = est; best = k; }
|
||||
}
|
||||
}
|
||||
// when we get here, best contains the filter type, and line_buffer contains the data
|
||||
filt[j*(x*n+1)] = (unsigned char) best;
|
||||
memcpy(filt+j*(x*n+1)+1, line_buffer, x*n);
|
||||
}
|
||||
free(line_buffer);
|
||||
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
|
||||
free(filt);
|
||||
if (!zlib) return 0;
|
||||
|
||||
// each tag requires 12 bytes of overhead
|
||||
out = (unsigned char *) malloc(8 + 12+13 + 12+zlen + 12);
|
||||
if (!out) return 0;
|
||||
*out_len = 8 + 12+13 + 12+zlen + 12;
|
||||
|
||||
o=out;
|
||||
memcpy(o,sig,8); o+= 8;
|
||||
stbi__wp32(o, 13); // header length
|
||||
stbi__wptag(o, "IHDR");
|
||||
stbi__wp32(o, x);
|
||||
stbi__wp32(o, y);
|
||||
*o++ = 8;
|
||||
*o++ = (unsigned char) ctype[n];
|
||||
*o++ = 0;
|
||||
*o++ = 0;
|
||||
*o++ = 0;
|
||||
stbi__wpcrc(&o,13);
|
||||
|
||||
stbi__wp32(o, zlen);
|
||||
stbi__wptag(o, "IDAT");
|
||||
memcpy(o, zlib, zlen); o += zlen; free(zlib);
|
||||
stbi__wpcrc(&o, zlen);
|
||||
|
||||
stbi__wp32(o,0);
|
||||
stbi__wptag(o, "IEND");
|
||||
stbi__wpcrc(&o,0);
|
||||
|
||||
assert(o == out + *out_len);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
|
||||
{
|
||||
FILE *f;
|
||||
int len;
|
||||
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
|
||||
if (!png) return 0;
|
||||
f = fopen(filename, "wb");
|
||||
if (!f) { free(png); return 0; }
|
||||
fwrite(png, 1, len, f);
|
||||
fclose(f);
|
||||
free(png);
|
||||
return 1;
|
||||
}
|
||||
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
/* Revision history
|
||||
|
||||
0.92 (2010-08-01)
|
||||
casts to unsigned char to fix warnings
|
||||
0.91 (2010-07-17)
|
||||
first public release
|
||||
0.90 first internal release
|
||||
*/
|
@ -1,10 +0,0 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
#if(UNIX)
|
||||
add_definitions(-fPIC)
|
||||
add_definitions(-g)
|
||||
add_definitions(-O2)
|
||||
add_definitions(-Wall)
|
||||
#endif(UNIX)
|
||||
|
||||
add_library(stb_vorbis stb_vorbis.c)
|
File diff suppressed because it is too large
Load Diff
@ -1,329 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// HEADER BEGINS HERE
|
||||
//
|
||||
|
||||
#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H
|
||||
#define STB_VORBIS_INCLUDE_STB_VORBIS_H
|
||||
|
||||
#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)
|
||||
#define STB_VORBIS_NO_STDIO 1
|
||||
#endif
|
||||
|
||||
#ifndef STB_VORBIS_NO_STDIO
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/////////// THREAD SAFETY
|
||||
|
||||
// Individual stb_vorbis* handles are not thread-safe; you cannot decode from
|
||||
// them from multiple threads at the same time. However, you can have multiple
|
||||
// stb_vorbis* handles and decode from them independently in multiple thrads.
|
||||
|
||||
|
||||
/////////// MEMORY ALLOCATION
|
||||
|
||||
// normally stb_vorbis uses malloc() to allocate memory at startup,
|
||||
// and alloca() to allocate temporary memory during a frame on the
|
||||
// stack. (Memory consumption will depend on the amount of setup
|
||||
// data in the file and how you set the compile flags for speed
|
||||
// vs. size. In my test files the maximal-size usage is ~150KB.)
|
||||
//
|
||||
// You can modify the wrapper functions in the source (setup_malloc,
|
||||
// setup_temp_malloc, temp_malloc) to change this behavior, or you
|
||||
// can use a simpler allocation model: you pass in a buffer from
|
||||
// which stb_vorbis will allocate _all_ its memory (including the
|
||||
// temp memory). "open" may fail with a VORBIS_outofmem if you
|
||||
// do not pass in enough data; there is no way to determine how
|
||||
// much you do need except to succeed (at which point you can
|
||||
// query get_info to find the exact amount required. yes I know
|
||||
// this is lame).
|
||||
//
|
||||
// If you pass in a non-NULL buffer of the type below, allocation
|
||||
// will occur from it as described above. Otherwise just pass NULL
|
||||
// to use malloc()/alloca()
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *alloc_buffer;
|
||||
int alloc_buffer_length_in_bytes;
|
||||
} stb_vorbis_alloc;
|
||||
|
||||
|
||||
/////////// FUNCTIONS USEABLE WITH ALL INPUT MODES
|
||||
|
||||
typedef struct stb_vorbis stb_vorbis;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int sample_rate;
|
||||
int channels;
|
||||
|
||||
unsigned int setup_memory_required;
|
||||
unsigned int setup_temp_memory_required;
|
||||
unsigned int temp_memory_required;
|
||||
|
||||
int max_frame_size;
|
||||
} stb_vorbis_info;
|
||||
|
||||
// get general information about the file
|
||||
extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f);
|
||||
|
||||
// get the last error detected (clears it, too)
|
||||
extern int stb_vorbis_get_error(stb_vorbis *f);
|
||||
|
||||
// close an ogg vorbis file and free all memory in use
|
||||
extern void stb_vorbis_close(stb_vorbis *f);
|
||||
|
||||
// this function returns the offset (in samples) from the beginning of the
|
||||
// file that will be returned by the next decode, if it is known, or -1
|
||||
// otherwise. after a flush_pushdata() call, this may take a while before
|
||||
// it becomes valid again.
|
||||
// NOT WORKING YET after a seek with PULLDATA API
|
||||
extern int stb_vorbis_get_sample_offset(stb_vorbis *f);
|
||||
|
||||
// returns the current seek point within the file, or offset from the beginning
|
||||
// of the memory buffer. In pushdata mode it returns 0.
|
||||
extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f);
|
||||
|
||||
/////////// PUSHDATA API
|
||||
|
||||
#ifndef STB_VORBIS_NO_PUSHDATA_API
|
||||
|
||||
// this API allows you to get blocks of data from any source and hand
|
||||
// them to stb_vorbis. you have to buffer them; stb_vorbis will tell
|
||||
// you how much it used, and you have to give it the rest next time;
|
||||
// and stb_vorbis may not have enough data to work with and you will
|
||||
// need to give it the same data again PLUS more. Note that the Vorbis
|
||||
// specification does not bound the size of an individual frame.
|
||||
|
||||
extern stb_vorbis *stb_vorbis_open_pushdata(
|
||||
unsigned char *datablock, int datablock_length_in_bytes,
|
||||
int *datablock_memory_consumed_in_bytes,
|
||||
int *error,
|
||||
stb_vorbis_alloc *alloc_buffer);
|
||||
// create a vorbis decoder by passing in the initial data block containing
|
||||
// the ogg&vorbis headers (you don't need to do parse them, just provide
|
||||
// the first N bytes of the file--you're told if it's not enough, see below)
|
||||
// on success, returns an stb_vorbis *, does not set error, returns the amount of
|
||||
// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes;
|
||||
// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed
|
||||
// if returns NULL and *error is VORBIS_need_more_data, then the input block was
|
||||
// incomplete and you need to pass in a larger block from the start of the file
|
||||
|
||||
extern int stb_vorbis_decode_frame_pushdata(
|
||||
stb_vorbis *f, unsigned char *datablock, int datablock_length_in_bytes,
|
||||
int *channels, // place to write number of float * buffers
|
||||
float ***output, // place to write float ** array of float * buffers
|
||||
int *samples // place to write number of output samples
|
||||
);
|
||||
// decode a frame of audio sample data if possible from the passed-in data block
|
||||
//
|
||||
// return value: number of bytes we used from datablock
|
||||
// possible cases:
|
||||
// 0 bytes used, 0 samples output (need more data)
|
||||
// N bytes used, 0 samples output (resynching the stream, keep going)
|
||||
// N bytes used, M samples output (one frame of data)
|
||||
// note that after opening a file, you will ALWAYS get one N-bytes,0-sample
|
||||
// frame, because Vorbis always "discards" the first frame.
|
||||
//
|
||||
// Note that on resynch, stb_vorbis will rarely consume all of the buffer,
|
||||
// instead only datablock_length_in_bytes-3 or less. This is because it wants
|
||||
// to avoid missing parts of a page header if they cross a datablock boundary,
|
||||
// without writing state-machiney code to record a partial detection.
|
||||
//
|
||||
// The number of channels returned are stored in *channels (which can be
|
||||
// NULL--it is always the same as the number of channels reported by
|
||||
// get_info). *output will contain an array of float* buffers, one per
|
||||
// channel. In other words, (*output)[0][0] contains the first sample from
|
||||
// the first channel, and (*output)[1][0] contains the first sample from
|
||||
// the second channel.
|
||||
|
||||
extern void stb_vorbis_flush_pushdata(stb_vorbis *f);
|
||||
// inform stb_vorbis that your next datablock will not be contiguous with
|
||||
// previous ones (e.g. you've seeked in the data); future attempts to decode
|
||||
// frames will cause stb_vorbis to resynchronize (as noted above), and
|
||||
// once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it
|
||||
// will begin decoding the _next_ frame.
|
||||
//
|
||||
// if you want to seek using pushdata, you need to seek in your file, then
|
||||
// call stb_vorbis_flush_pushdata(), then start calling decoding, then once
|
||||
// decoding is returning you data, call stb_vorbis_get_sample_offset, and
|
||||
// if you don't like the result, seek your file again and repeat.
|
||||
#endif
|
||||
|
||||
|
||||
////////// PULLING INPUT API
|
||||
|
||||
#ifndef STB_VORBIS_NO_PULLDATA_API
|
||||
// This API assumes stb_vorbis is allowed to pull data from a source--
|
||||
// either a block of memory containing the _entire_ vorbis stream, or a
|
||||
// FILE * that you or it create, or possibly some other reading mechanism
|
||||
// if you go modify the source to replace the FILE * case with some kind
|
||||
// of callback to your code. (But if you don't support seeking, you may
|
||||
// just want to go ahead and use pushdata.)
|
||||
|
||||
#if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
|
||||
extern int stb_vorbis_decode_filename(char *filename, int *channels, short **output);
|
||||
#endif
|
||||
extern int stb_vorbis_decode_memory(unsigned char *mem, int len, int *channels, short **output);
|
||||
// decode an entire file and output the data interleaved into a malloc()ed
|
||||
// buffer stored in *output. The return value is the number of samples
|
||||
// decoded, or -1 if the file could not be opened or was not an ogg vorbis file.
|
||||
// When you're done with it, just free() the pointer returned in *output.
|
||||
|
||||
extern stb_vorbis * stb_vorbis_open_memory(unsigned char *data, int len,
|
||||
int *error, stb_vorbis_alloc *alloc_buffer);
|
||||
// create an ogg vorbis decoder from an ogg vorbis stream in memory (note
|
||||
// this must be the entire stream!). on failure, returns NULL and sets *error
|
||||
|
||||
#ifndef STB_VORBIS_NO_STDIO
|
||||
extern stb_vorbis * stb_vorbis_open_filename(char *filename,
|
||||
int *error, stb_vorbis_alloc *alloc_buffer);
|
||||
// create an ogg vorbis decoder from a filename via fopen(). on failure,
|
||||
// returns NULL and sets *error (possibly to VORBIS_file_open_failure).
|
||||
|
||||
extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
|
||||
int *error, stb_vorbis_alloc *alloc_buffer);
|
||||
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
|
||||
// the _current_ seek point (ftell). on failure, returns NULL and sets *error.
|
||||
// note that stb_vorbis must "own" this stream; if you seek it in between
|
||||
// calls to stb_vorbis, it will become confused. Morever, if you attempt to
|
||||
// perform stb_vorbis_seek_*() operations on this file, it will assume it
|
||||
// owns the _entire_ rest of the file after the start point. Use the next
|
||||
// function, stb_vorbis_open_file_section(), to limit it.
|
||||
|
||||
extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close,
|
||||
int *error, stb_vorbis_alloc *alloc_buffer, unsigned int len);
|
||||
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
|
||||
// the _current_ seek point (ftell); the stream will be of length 'len' bytes.
|
||||
// on failure, returns NULL and sets *error. note that stb_vorbis must "own"
|
||||
// this stream; if you seek it in between calls to stb_vorbis, it will become
|
||||
// confused.
|
||||
#endif
|
||||
|
||||
extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number);
|
||||
extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number);
|
||||
// NOT WORKING YET
|
||||
// these functions seek in the Vorbis file to (approximately) 'sample_number'.
|
||||
// after calling seek_frame(), the next call to get_frame_*() will include
|
||||
// the specified sample. after calling stb_vorbis_seek(), the next call to
|
||||
// stb_vorbis_get_samples_* will start with the specified sample. If you
|
||||
// do not need to seek to EXACTLY the target sample when using get_samples_*,
|
||||
// you can also use seek_frame().
|
||||
|
||||
extern void stb_vorbis_seek_start(stb_vorbis *f);
|
||||
// this function is equivalent to stb_vorbis_seek(f,0), but it
|
||||
// actually works
|
||||
|
||||
extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f);
|
||||
extern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f);
|
||||
// these functions return the total length of the vorbis stream
|
||||
|
||||
extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output);
|
||||
// decode the next frame and return the number of samples. the number of
|
||||
// channels returned are stored in *channels (which can be NULL--it is always
|
||||
// the same as the number of channels reported by get_info). *output will
|
||||
// contain an array of float* buffers, one per channel. These outputs will
|
||||
// be overwritten on the next call to stb_vorbis_get_frame_*.
|
||||
//
|
||||
// You generally should not intermix calls to stb_vorbis_get_frame_*()
|
||||
// and stb_vorbis_get_samples_*(), since the latter calls the former.
|
||||
|
||||
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
|
||||
extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts);
|
||||
extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples);
|
||||
#endif
|
||||
// decode the next frame and return the number of samples per channel. the
|
||||
// data is coerced to the number of channels you request according to the
|
||||
// channel coercion rules (see below). You must pass in the size of your
|
||||
// buffer(s) so that stb_vorbis will not overwrite the end of the buffer.
|
||||
// The maximum buffer size needed can be gotten from get_info(); however,
|
||||
// the Vorbis I specification implies an absolute maximum of 4096 samples
|
||||
// per channel. Note that for interleaved data, you pass in the number of
|
||||
// shorts (the size of your array), but the return value is the number of
|
||||
// samples per channel, not the total number of samples.
|
||||
|
||||
// Channel coercion rules:
|
||||
// Let M be the number of channels requested, and N the number of channels present,
|
||||
// and Cn be the nth channel; let stereo L be the sum of all L and center channels,
|
||||
// and stereo R be the sum of all R and center channels (channel assignment from the
|
||||
// vorbis spec).
|
||||
// M N output
|
||||
// 1 k sum(Ck) for all k
|
||||
// 2 * stereo L, stereo R
|
||||
// k l k > l, the first l channels, then 0s
|
||||
// k l k <= l, the first k channels
|
||||
// Note that this is not _good_ surround etc. mixing at all! It's just so
|
||||
// you get something useful.
|
||||
|
||||
extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats);
|
||||
extern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples);
|
||||
// gets num_samples samples, not necessarily on a frame boundary--this requires
|
||||
// buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES.
|
||||
// Returns the number of samples stored per channel; it may be less than requested
|
||||
// at the end of the file. If there are no more samples in the file, returns 0.
|
||||
|
||||
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
|
||||
extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts);
|
||||
extern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples);
|
||||
#endif
|
||||
// gets num_samples samples, not necessarily on a frame boundary--this requires
|
||||
// buffering so you have to supply the buffers. Applies the coercion rules above
|
||||
// to produce 'channels' channels. Returns the number of samples stored per channel;
|
||||
// it may be less than requested at the end of the file. If there are no more
|
||||
// samples in the file, returns 0.
|
||||
|
||||
#endif
|
||||
|
||||
//////// ERROR CODES
|
||||
|
||||
enum STBVorbisError
|
||||
{
|
||||
VORBIS__no_error,
|
||||
|
||||
VORBIS_need_more_data=1, // not a real error
|
||||
|
||||
VORBIS_invalid_api_mixing, // can't mix API modes
|
||||
VORBIS_outofmem, // not enough memory
|
||||
VORBIS_feature_not_supported, // uses floor 0
|
||||
VORBIS_too_many_channels, // STB_VORBIS_MAX_CHANNELS is too small
|
||||
VORBIS_file_open_failure, // fopen() failed
|
||||
VORBIS_seek_without_length, // can't seek in unknown-length file
|
||||
|
||||
VORBIS_unexpected_eof=10, // file is truncated?
|
||||
VORBIS_seek_invalid, // seek past EOF
|
||||
|
||||
// decoding errors (corrupt/invalid stream) -- you probably
|
||||
// don't care about the exact details of these
|
||||
|
||||
// vorbis errors:
|
||||
VORBIS_invalid_setup=20,
|
||||
VORBIS_invalid_stream,
|
||||
|
||||
// ogg errors:
|
||||
VORBIS_missing_capture_pattern=30,
|
||||
VORBIS_invalid_stream_structure_version,
|
||||
VORBIS_continued_packet_flag_invalid,
|
||||
VORBIS_incorrect_stream_serial_number,
|
||||
VORBIS_invalid_first_page,
|
||||
VORBIS_bad_packet_type,
|
||||
VORBIS_cant_find_last_page,
|
||||
VORBIS_seek_failed,
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // STB_VORBIS_INCLUDE_STB_VORBIS_H
|
||||
//
|
||||
// HEADER ENDS HERE
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1,89 +0,0 @@
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <commdlg.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "util/text/utf8.h"
|
||||
|
||||
// For desktop operating systems only. Stubbed out on Android.
|
||||
// Simplified as this will only be used in utilities / temp code.
|
||||
// An false returned means cancel;
|
||||
bool OpenFileDialog(const char *title, const char *extension, std::string *filename)
|
||||
{
|
||||
std::wstring wtitle = ConvertUTF8ToWString(std::string(title));
|
||||
std::wstring wext = ConvertUTF8ToWString(std::string(extension));
|
||||
|
||||
OPENFILENAME of;
|
||||
memset(&of, 0, sizeof(of));
|
||||
wchar_t buffer[512] = {0};
|
||||
of.lStructSize = sizeof(OPENFILENAME);
|
||||
of.hInstance = 0;
|
||||
of.hwndOwner = GetActiveWindow();
|
||||
|
||||
// These weird strings with zeroes in them can't be dealt with using normal string
|
||||
// functions, so here we go - evil hackery.
|
||||
wchar_t filter[256] = L"XXX files\0*.XXX\0\0";
|
||||
memcpy(filter, wext.c_str(), 3 * sizeof(wchar_t));
|
||||
memcpy(filter + 12, wext.c_str(), 3 * sizeof(wchar_t));
|
||||
of.lpstrFilter = filter;
|
||||
|
||||
of.lpstrDefExt = wext.c_str();
|
||||
of.lpstrFile = buffer;
|
||||
of.nMaxFile = 511;
|
||||
|
||||
of.Flags = OFN_FILEMUSTEXIST;
|
||||
if (!GetOpenFileName(&of)) return false;
|
||||
*filename = ConvertWStringToUTF8(of.lpstrFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveFileDialog(const char *title, const char *extension, std::string *filename) {
|
||||
std::wstring wtitle = ConvertUTF8ToWString(std::string(title));
|
||||
std::wstring wext = ConvertUTF8ToWString(std::string(extension));
|
||||
|
||||
OPENFILENAME of;
|
||||
memset(&of, 0, sizeof(of));
|
||||
wchar_t buffer[512] = {0};
|
||||
of.lStructSize = sizeof(OPENFILENAME);
|
||||
of.hInstance = 0;
|
||||
of.hwndOwner = GetActiveWindow();
|
||||
|
||||
// These weird strings with zeroes in them can't be dealt with using normal string
|
||||
// functions, so here we go - evil hackery.
|
||||
wchar_t filter[256] = L"XXX files\0*.XXX\0\0";
|
||||
memcpy(filter, wext.c_str(), 3 * sizeof(wchar_t));
|
||||
memcpy(filter + 12, wext.c_str(), 3 * sizeof(wchar_t));
|
||||
of.lpstrFilter = filter;
|
||||
|
||||
of.lpstrDefExt = wext.c_str();
|
||||
of.lpstrFile = buffer;
|
||||
of.nMaxFile = 511;
|
||||
|
||||
of.Flags = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
|
||||
if (!GetSaveFileName(&of))
|
||||
return false;
|
||||
*filename = ConvertWStringToUTF8(of.lpstrFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <string>
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
bool OpenFileDialog(const char *title, const char *extension, std::string *filename)
|
||||
{
|
||||
ELOG("Asked for OpenFileDialog, not present on this platform.");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SaveFileDialog(const char *title, const char *extension, std::string *filename)
|
||||
{
|
||||
ELOG("Asked for SaveFileDialog, not present on this platform.");
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "file/dialog.h"
|
||||
|
||||
bool OpenFileDialog(const char *title, const char *extension, std::string *filename);
|
||||
bool SaveFileDialog(const char *title, const char *extension, std::string *filename);
|
@ -1,9 +1,7 @@
|
||||
set(SRCS
|
||||
gl_debug_log.cpp
|
||||
gl_lost_manager.cpp
|
||||
texture.cpp
|
||||
texture_atlas.cpp
|
||||
texture_gen.cpp)
|
||||
texture_atlas.cpp)
|
||||
|
||||
set(SRCS ${SRCS})
|
||||
|
||||
|
@ -1,376 +0,0 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ext/rg_etc1/rg_etc1.h"
|
||||
#include "ext/jpge/jpgd.h"
|
||||
#include "image/png_load.h"
|
||||
#include "image/zim_load.h"
|
||||
#include "base/logging.h"
|
||||
#include "gfx/texture.h"
|
||||
#include "gfx/texture_gen.h"
|
||||
#include "gfx/gl_debug_log.h"
|
||||
#include "gfx/gl_lost_manager.h"
|
||||
#include "gfx/gl_common.h"
|
||||
#include "gfx_es2/gpu_features.h"
|
||||
|
||||
Texture::Texture() : id_(0) {
|
||||
CheckGLExtensions();
|
||||
register_gl_resource_holder(this);
|
||||
}
|
||||
|
||||
Texture::~Texture() {
|
||||
unregister_gl_resource_holder(this);
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void Texture::Destroy() {
|
||||
if (id_) {
|
||||
glDeleteTextures(1, &id_);
|
||||
id_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Texture::GLLost() {
|
||||
if (!filename_.empty()) {
|
||||
Load(filename_.c_str());
|
||||
ILOG("Reloaded lost texture %s", filename_.c_str());
|
||||
} else {
|
||||
WLOG("Texture %p cannot be restored - has no filename", this);
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
static void SetTextureParameters(int zim_flags) {
|
||||
GLenum wrap = GL_REPEAT;
|
||||
if (zim_flags & ZIM_CLAMP)
|
||||
wrap = GL_CLAMP_TO_EDGE;
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap);
|
||||
GL_CHECK();
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
if ((zim_flags & (ZIM_HAS_MIPS | ZIM_GEN_MIPS))) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
}
|
||||
GL_CHECK();
|
||||
}
|
||||
|
||||
bool Texture::Load(const char *filename) {
|
||||
// hook for generated textures
|
||||
if (!memcmp(filename, "gen:", 4)) {
|
||||
int bpp, w, h;
|
||||
bool clamp;
|
||||
uint8_t *data = generateTexture(filename, bpp, w, h, clamp);
|
||||
if (!data)
|
||||
return false;
|
||||
glGenTextures(1, &id_);
|
||||
glBindTexture(GL_TEXTURE_2D, id_);
|
||||
if (bpp == 1) {
|
||||
if (gl_extensions.IsGLES) {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
|
||||
} else {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, 1, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
|
||||
}
|
||||
} else {
|
||||
FLOG("unsupported");
|
||||
}
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
delete [] data;
|
||||
return true;
|
||||
}
|
||||
|
||||
filename_ = filename;
|
||||
|
||||
// Currently here are a bunch of project-specific workarounds.
|
||||
// They shouldn't really hurt anything else very much though.
|
||||
|
||||
size_t len = strlen(filename);
|
||||
char fn[1024];
|
||||
strncpy(fn, filename, sizeof(fn));
|
||||
fn[1023] = 0;
|
||||
bool zim = false;
|
||||
if (!strcmp("dds", &filename[len-3])) {
|
||||
strcpy(&fn[len-3], "zim");
|
||||
zim = true;
|
||||
}
|
||||
if (!strcmp("6TX", &filename[len-3]) || !strcmp("6tx", &filename[len-3])) {
|
||||
ILOG("Detected 6TX %s", filename);
|
||||
strcpy(&fn[len-3], "zim");
|
||||
zim = true;
|
||||
}
|
||||
for (int i = 0; i < (int)strlen(fn); i++) {
|
||||
if (fn[i] == '\\') fn[i] = '/';
|
||||
}
|
||||
|
||||
if (fn[0] == 'm') fn[0] = 'M';
|
||||
const char *name = fn;
|
||||
if (zim && 0==memcmp(name, "Media/textures/", strlen("Media/textures"))) name += strlen("Media/textures/");
|
||||
len = strlen(name);
|
||||
if (!strcmp("png", &name[len-3]) || !strcmp("PNG", &name[len-3])) {
|
||||
if (!LoadPNG(fn)) {
|
||||
WLOG("WARNING: Failed to load .png %s, falling back to ugly gray XOR pattern!", fn);
|
||||
LoadXOR();
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else if (!strcmp("zim", &name[len-3])) {
|
||||
if (LoadZIM(name)) {
|
||||
return true;
|
||||
} else {
|
||||
WLOG("WARNING: Failed to load .zim texture %s, falling back to ugly gray XOR pattern!", fn);
|
||||
LoadXOR();
|
||||
return false;
|
||||
}
|
||||
} else if (!strcmp("jpg", &name[len-3]) || !strcmp("JPG", &name[len-3]) ||
|
||||
!strcmp("jpeg", &name[len-4]) || !strcmp("JPEG", &name[len-4])) {
|
||||
if (!LoadJPEG(fn)) {
|
||||
WLOG("WARNING: Failed to load jpeg %s, falling back to ugly gray XOR pattern!", fn);
|
||||
LoadXOR();
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else if (!name || !strlen(name)) {
|
||||
ELOG("Failed to identify image file %s by extension", name);
|
||||
} else {
|
||||
ELOG("Cannot load a texture with an empty filename");
|
||||
}
|
||||
LoadXOR();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Texture::LoadPNG(const char *filename, bool genMips) {
|
||||
unsigned char *image_data;
|
||||
if (1 != pngLoad(filename, &width_, &height_, &image_data, false)) {
|
||||
return false;
|
||||
}
|
||||
GL_CHECK();
|
||||
glGenTextures(1, &id_);
|
||||
glBindTexture(GL_TEXTURE_2D, id_);
|
||||
SetTextureParameters(genMips ? ZIM_GEN_MIPS : ZIM_CLAMP);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, image_data);
|
||||
if (genMips) {
|
||||
if (gl_extensions.ARB_framebuffer_object) {
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
} else {
|
||||
#ifndef USING_GLES2
|
||||
glGenerateMipmapEXT(GL_TEXTURE_2D);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
GL_CHECK();
|
||||
free(image_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Texture::LoadJPEG(const char *filename, bool genMips) {
|
||||
ILOG("Loading jpeg %s", filename);
|
||||
unsigned char *image_data;
|
||||
int actual_comps;
|
||||
image_data = jpgd::decompress_jpeg_image_from_file(filename, &width_, &height_, &actual_comps, 4);
|
||||
if (!image_data) {
|
||||
ELOG("jpeg: image data returned was 0");
|
||||
return false;
|
||||
}
|
||||
ILOG("Jpeg decoder failed to get RGB, got: %i x %i x %i", actual_comps, width_, height_);
|
||||
ILOG("First four bytes: %i %i %i %i", image_data[0], image_data[1], image_data[2], image_data[3]);
|
||||
|
||||
GL_CHECK();
|
||||
glGenTextures(1, &id_);
|
||||
glBindTexture(GL_TEXTURE_2D, id_);
|
||||
SetTextureParameters(genMips ? ZIM_GEN_MIPS : ZIM_CLAMP);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
|
||||
if (genMips) {
|
||||
if (gl_extensions.ARB_framebuffer_object) {
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
} else {
|
||||
#ifndef USING_GLES2
|
||||
glGenerateMipmapEXT(GL_TEXTURE_2D);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
GL_CHECK();
|
||||
free(image_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Texture::LoadPNG(const uint8_t *data, size_t size, bool genMips) {
|
||||
unsigned char *image_data;
|
||||
if (1 != pngLoadPtr(data, size, &width_, &height_, &image_data, false)) {
|
||||
return false;
|
||||
}
|
||||
GL_CHECK();
|
||||
// TODO: should check for power of 2 tex size and disallow genMips when not.
|
||||
glGenTextures(1, &id_);
|
||||
glBindTexture(GL_TEXTURE_2D, id_);
|
||||
SetTextureParameters(genMips ? ZIM_GEN_MIPS : ZIM_CLAMP);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
|
||||
if (genMips) {
|
||||
if (gl_extensions.ARB_framebuffer_object) {
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
} else {
|
||||
#ifndef USING_GLES2
|
||||
glGenerateMipmapEXT(GL_TEXTURE_2D);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
GL_CHECK();
|
||||
free(image_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Texture::LoadXOR() {
|
||||
width_ = height_ = 256;
|
||||
unsigned char *buf = new unsigned char[width_*height_*4];
|
||||
for (int y = 0; y < 256; y++) {
|
||||
for (int x = 0; x < 256; x++) {
|
||||
buf[(y*width_ + x)*4 + 0] = x^y;
|
||||
buf[(y*width_ + x)*4 + 1] = x^y;
|
||||
buf[(y*width_ + x)*4 + 2] = x^y;
|
||||
buf[(y*width_ + x)*4 + 3] = 0xFF;
|
||||
}
|
||||
}
|
||||
GL_CHECK();
|
||||
glGenTextures(1, &id_);
|
||||
glBindTexture(GL_TEXTURE_2D, id_);
|
||||
SetTextureParameters(ZIM_GEN_MIPS);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, buf);
|
||||
if(gl_extensions.ARB_framebuffer_object){
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
}else{
|
||||
#ifndef USING_GLES2
|
||||
glGenerateMipmapEXT(GL_TEXTURE_2D);
|
||||
#endif
|
||||
}
|
||||
GL_CHECK();
|
||||
delete [] buf;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#if !defined(USING_GLES2) || defined(IOS)
|
||||
|
||||
// Allocates using new[], doesn't free.
|
||||
uint8_t *ETC1ToRGBA(uint8_t *etc1, int width, int height) {
|
||||
uint8_t *rgba = new uint8_t[width * height * 4];
|
||||
memset(rgba, 0xFF, width * height * 4);
|
||||
for (int y = 0; y < height; y += 4) {
|
||||
for (int x = 0; x < width; x += 4) {
|
||||
rg_etc1::unpack_etc1_block(etc1 + ((y / 4) * width/4 + (x / 4)) * 8,
|
||||
(uint32_t *)rgba + (y * width + x), width, false);
|
||||
}
|
||||
}
|
||||
return rgba;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool Texture::LoadZIM(const char *filename) {
|
||||
uint8_t *image_data[ZIM_MAX_MIP_LEVELS];
|
||||
int width[ZIM_MAX_MIP_LEVELS];
|
||||
int height[ZIM_MAX_MIP_LEVELS];
|
||||
|
||||
int flags;
|
||||
int num_levels = ::LoadZIM(filename, &width[0], &height[0], &flags, &image_data[0]);
|
||||
if (!num_levels)
|
||||
return false;
|
||||
if (num_levels >= ZIM_MAX_MIP_LEVELS)
|
||||
return false;
|
||||
width_ = width[0];
|
||||
height_ = height[0];
|
||||
int data_type = GL_UNSIGNED_BYTE;
|
||||
int colors = GL_RGBA;
|
||||
int storage = GL_RGBA;
|
||||
bool compressed = false;
|
||||
switch (flags & ZIM_FORMAT_MASK) {
|
||||
case ZIM_RGBA8888:
|
||||
data_type = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case ZIM_RGBA4444:
|
||||
data_type = GL_UNSIGNED_SHORT_4_4_4_4;
|
||||
break;
|
||||
case ZIM_RGB565:
|
||||
data_type = GL_UNSIGNED_SHORT_5_6_5;
|
||||
colors = GL_RGB;
|
||||
storage = GL_RGB;
|
||||
break;
|
||||
case ZIM_ETC1:
|
||||
compressed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
GL_CHECK();
|
||||
|
||||
glGenTextures(1, &id_);
|
||||
glBindTexture(GL_TEXTURE_2D, id_);
|
||||
SetTextureParameters(flags);
|
||||
|
||||
if (compressed) {
|
||||
for (int l = 0; l < num_levels; l++) {
|
||||
int data_w = width[l];
|
||||
int data_h = height[l];
|
||||
if (data_w < 4) data_w = 4;
|
||||
if (data_h < 4) data_h = 4;
|
||||
#if defined(USING_GLES2) && !defined(IOS)
|
||||
int compressed_image_bytes = data_w * data_h / 2;
|
||||
glCompressedTexImage2D(GL_TEXTURE_2D, l, GL_ETC1_RGB8_OES, width[l], height[l], 0, compressed_image_bytes, image_data[l]);
|
||||
GL_CHECK();
|
||||
#else
|
||||
// TODO: OpenGL 4.3+ accepts ETC1 so we should not have to do this anymore on those cards.
|
||||
// Also, iOS does not have support for ETC1 compressed textures so we just decompress.
|
||||
// TODO: Use PVR texture compression on iOS.
|
||||
image_data[l] = ETC1ToRGBA(image_data[l], data_w, data_h);
|
||||
glTexImage2D(GL_TEXTURE_2D, l, GL_RGBA, width[l], height[l], 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, image_data[l]);
|
||||
#endif
|
||||
}
|
||||
GL_CHECK();
|
||||
#if !defined(USING_GLES2)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, num_levels - 2);
|
||||
#endif
|
||||
} else {
|
||||
for (int l = 0; l < num_levels; l++) {
|
||||
glTexImage2D(GL_TEXTURE_2D, l, storage, width[l], height[l], 0,
|
||||
colors, data_type, image_data[l]);
|
||||
}
|
||||
if (num_levels == 1 && (flags & ZIM_GEN_MIPS)) {
|
||||
if(gl_extensions.ARB_framebuffer_object) {
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
}else{
|
||||
#ifndef USING_GLES2
|
||||
glGenerateMipmapEXT(GL_TEXTURE_2D);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
SetTextureParameters(flags);
|
||||
|
||||
GL_CHECK();
|
||||
// Only free the top level, since the allocation is used for all of them.
|
||||
free(image_data[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Texture::Bind(int stage) {
|
||||
GL_CHECK();
|
||||
if (stage != -1)
|
||||
glActiveTexture(GL_TEXTURE0 + stage);
|
||||
glBindTexture(GL_TEXTURE_2D, id_);
|
||||
GL_CHECK();
|
||||
}
|
||||
|
||||
void Texture::Unbind(int stage) {
|
||||
GL_CHECK();
|
||||
if (stage != -1)
|
||||
glActiveTexture(GL_TEXTURE0 + stage);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
GL_CHECK();
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Load and manage OpenGL textures easily. Supports ETC1 compressed texture with mipmaps
|
||||
// in the custom ZIM format.
|
||||
|
||||
// This is deprecated - start using Thin3D instead.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "gfx/gl_lost_manager.h"
|
||||
|
||||
class Texture : public GfxResourceHolder {
|
||||
public:
|
||||
Texture();
|
||||
~Texture();
|
||||
|
||||
// Deduces format from the filename.
|
||||
// If loading fails, will load a 256x256 XOR texture.
|
||||
// If filename begins with "gen:", will defer to texture_gen.cpp/h.
|
||||
// When format is known, it's fine to use LoadZIM etc directly.
|
||||
// Those will NOT auto-fall back to xor texture however!
|
||||
bool Load(const char *filename);
|
||||
void Bind(int stage = -1);
|
||||
void Destroy();
|
||||
|
||||
// PNG from memory buffer
|
||||
bool LoadPNG(const uint8_t *data, size_t size, bool genMips = true);
|
||||
bool LoadZIM(const char *filename);
|
||||
bool LoadPNG(const char *filename, bool genMips = true);
|
||||
bool LoadJPEG(const char *filename, bool genMips = true);
|
||||
|
||||
unsigned int Handle() const {
|
||||
return id_;
|
||||
}
|
||||
|
||||
virtual void GLLost();
|
||||
std::string filename() const { return filename_; }
|
||||
|
||||
static void Unbind(int stage = -1);
|
||||
|
||||
int Width() const { return width_; }
|
||||
int Height() const { return height_; }
|
||||
|
||||
private:
|
||||
bool LoadXOR(); // Loads a placeholder texture.
|
||||
|
||||
std::string filename_;
|
||||
#ifdef METRO
|
||||
ID3D11Texture2D *tex_;
|
||||
#endif
|
||||
unsigned int id_;
|
||||
int width_, height_;
|
||||
};
|
@ -1,271 +0,0 @@
|
||||
// WIP, please ignore
|
||||
#include <d3d11_1.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if !defined(USING_GLES2)
|
||||
#include "image/png_load.h"
|
||||
#include "ext/etcpack/etcdec.h"
|
||||
#endif
|
||||
|
||||
#include "image/zim_load.h"
|
||||
#include "base/logging.h"
|
||||
#include "gfx/texture.h"
|
||||
#include "gfx/texture_gen.h"
|
||||
#include "gfx/gl_debug_log.h"
|
||||
#include "gfx/gl_lost_manager.h"
|
||||
|
||||
Texture::Texture() : tex_(0) {
|
||||
register_gl_resource_holder(this);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void Texture::Destroy() {
|
||||
if (tex_) {
|
||||
tex_->Release();
|
||||
tex_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Texture::GLLost() {
|
||||
ILOG("Reloading lost texture %s", filename_.c_str());
|
||||
Load(filename_.c_str());
|
||||
}
|
||||
|
||||
Texture::~Texture() {
|
||||
unregister_gl_resource_holder(this);
|
||||
Destroy();
|
||||
}
|
||||
|
||||
static void SetTextureParameters(int zim_flags) {
|
||||
/*
|
||||
GLenum wrap = GL_REPEAT;
|
||||
if (zim_flags & ZIM_CLAMP) wrap = GL_CLAMP_TO_EDGE;
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap);
|
||||
GL_CHECK();
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
if ((zim_flags & (ZIM_HAS_MIPS | ZIM_GEN_MIPS))) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
}
|
||||
GL_CHECK();*/
|
||||
}
|
||||
|
||||
bool Texture::Load(const char *filename) {
|
||||
// hook for generated textures
|
||||
if (!memcmp(filename, "gen:", 4)) {
|
||||
// TODO
|
||||
// return false;
|
||||
tex_ = (LPVOID)generateTexture(filename);
|
||||
if (tex_) {
|
||||
this->filename_ = filename;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
filename_ = filename;
|
||||
// Currently contains many Rollerball-specific workarounds.
|
||||
// They shouldn't really hurt anything else very much though.
|
||||
int len = strlen(filename);
|
||||
char fn[256];
|
||||
strcpy(fn, filename);
|
||||
bool zim = false;
|
||||
if (!strcmp("dds", &filename[len-3])) {
|
||||
strcpy(&fn[len-3], "zim");
|
||||
zim = true;
|
||||
}
|
||||
if (!strcmp("6TX", &filename[len-3]) || !strcmp("6tx", &filename[len-3])) {
|
||||
ILOG("Detected 6TX %s", filename);
|
||||
strcpy(&fn[len-3], "zim");
|
||||
zim = true;
|
||||
}
|
||||
for (int i = 0; i < (int)strlen(fn); i++) {
|
||||
if (fn[i] == '\\') fn[i] = '/';
|
||||
}
|
||||
|
||||
if (fn[0] == 'm') fn[0] = 'M';
|
||||
const char *name = fn;
|
||||
if (zim && 0 == memcmp(name, "Media/textures/", strlen("Media/textures"))) name += strlen("Media/textures/");
|
||||
len = strlen(name);
|
||||
#if !defined(USING_GLES2)
|
||||
if (!strcmp("png", &name[len-3]) ||
|
||||
!strcmp("PNG", &name[len-3])) {
|
||||
if (!LoadPNG(fn)) {
|
||||
LoadXOR();
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (!strcmp("zim", &name[len-3])) {
|
||||
if (!LoadZIM(name)) {
|
||||
LoadXOR();
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
LoadXOR();
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef METRO
|
||||
#if !defined(USING_GLES2)
|
||||
bool Texture::LoadPNG(const char *filename) {
|
||||
unsigned char *image_data;
|
||||
if (1 != pngLoad(filename, &width_, &height_, &image_data, false)) {
|
||||
return false;
|
||||
}
|
||||
GL_CHECK();
|
||||
glGenTextures(1, &id_);
|
||||
glBindTexture(GL_TEXTURE_2D, id_);
|
||||
SetTextureParameters(ZIM_GEN_MIPS);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, image_data);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
GL_CHECK();
|
||||
free(image_data);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
bool Texture::LoadXOR() {
|
||||
width_ = height_ = 256;
|
||||
unsigned char *buf = new unsigned char[width_*height_*4];
|
||||
for (int y = 0; y < 256; y++) {
|
||||
for (int x = 0; x < 256; x++) {
|
||||
buf[(y*width_ + x)*4 + 0] = x^y;
|
||||
buf[(y*width_ + x)*4 + 1] = x^y;
|
||||
buf[(y*width_ + x)*4 + 2] = x^y;
|
||||
buf[(y*width_ + x)*4 + 3] = 0xFF;
|
||||
}
|
||||
}
|
||||
GL_CHECK();
|
||||
ID3D11Device *ctx;
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
desc.Width = width_;
|
||||
desc.Height = height_;
|
||||
desc.MipLevels = 0;
|
||||
desc.ArraySize = 1;
|
||||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.CPUAccessFlags = 0;
|
||||
desc.MiscFlags = 0;
|
||||
if (FAILED(ctx->CreateTexture2D(&desc, 0, &tex_))) {
|
||||
FLOG("Failed creating XOR texture");
|
||||
}
|
||||
SetTextureParameters(ZIM_GEN_MIPS);
|
||||
GL_CHECK();
|
||||
delete [] buf;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#if !defined(USING_GLES2)
|
||||
|
||||
// Allocates using new[], doesn't free.
|
||||
uint8_t *ETC1ToRGBA(uint8_t *etc1, int width, int height) {
|
||||
uint8_t *rgba = new uint8_t[width * height * 4];
|
||||
memset(rgba, 0xFF, width * height * 4);
|
||||
for (int y = 0; y < height; y += 4) {
|
||||
for (int x = 0; x < width; x += 4) {
|
||||
DecompressBlock(etc1 + ((y / 4) * width/4 + (x / 4)) * 8,
|
||||
rgba + (y * width + x) * 4, width, 255);
|
||||
}
|
||||
}
|
||||
return rgba;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool Texture::LoadZIM(const char *filename) {
|
||||
uint8_t *image_data[ZIM_MAX_MIP_LEVELS];
|
||||
int width[ZIM_MAX_MIP_LEVELS];
|
||||
int height[ZIM_MAX_MIP_LEVELS];
|
||||
|
||||
int flags;
|
||||
int num_levels = ::LoadZIM(filename, &width[0], &height[0], &flags, &image_data[0]);
|
||||
if (!num_levels)
|
||||
return false;
|
||||
width_ = width[0];
|
||||
height_ = height[0];
|
||||
int data_type = GL_UNSIGNED_BYTE;
|
||||
int colors = GL_RGBA;
|
||||
int storage = GL_RGBA;
|
||||
bool compressed = false;
|
||||
switch (flags & ZIM_FORMAT_MASK) {
|
||||
case ZIM_RGBA8888:
|
||||
data_type = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case ZIM_RGBA4444:
|
||||
data_type = DXGI_FORMAT_B4G4R4A4_UNORM;
|
||||
break;
|
||||
case ZIM_RGB565:
|
||||
data_type = DXGI_FORMAT_B5G6R5_UNORM;
|
||||
colors = GL_RGB;
|
||||
storage = GL_RGB;
|
||||
break;
|
||||
case ZIM_ETC1:
|
||||
compressed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
GL_CHECK();
|
||||
//glGenTextures(1, &id_);
|
||||
//glBindTexture(GL_TEXTURE_2D, id_);
|
||||
SetTextureParameters(flags);
|
||||
|
||||
if (compressed) {
|
||||
for (int l = 0; l < num_levels; l++) {
|
||||
int data_w = width[l];
|
||||
int data_h = height[l];
|
||||
if (data_w < 4) data_w = 4;
|
||||
if (data_h < 4) data_h = 4;
|
||||
#if defined(USING_GLES2)
|
||||
int compressed_image_bytes = data_w * data_h / 2;
|
||||
glCompressedTexImage2D(GL_TEXTURE_2D, l, GL_ETC1_RGB8_OES, width[l], height[l], 0, compressed_image_bytes, image_data[l]);
|
||||
GL_CHECK();
|
||||
#else
|
||||
//image_data[l] = ETC1ToRGBA(image_data[l], data_w, data_h);
|
||||
//glTexImage2D(GL_TEXTURE_2D, l, GL_RGBA, width[l], height[l], 0,
|
||||
// GL_RGBA, GL_UNSIGNED_BYTE, image_data[l]);
|
||||
#endif
|
||||
}
|
||||
GL_CHECK();
|
||||
#if !defined(USING_GLES2)
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, num_levels - 2);
|
||||
#endif
|
||||
} else {
|
||||
for (int l = 0; l < num_levels; l++) {
|
||||
//glTexImage2D(GL_TEXTURE_2D, l, storage, width[l], height[l], 0,
|
||||
// colors, data_type, image_data[l]);
|
||||
}
|
||||
if (num_levels == 1 && (flags & ZIM_GEN_MIPS)) {
|
||||
//glGenerateMipmap(GL_TEXTURE_2D);
|
||||
}
|
||||
}
|
||||
SetTextureParameters(flags);
|
||||
|
||||
GL_CHECK();
|
||||
// Only free the top level, since the allocation is used for all of them.
|
||||
delete [] image_data[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
void Texture::Bind(int stage) {
|
||||
GL_CHECK();
|
||||
//if (stage != -1)
|
||||
// glActiveTexture(GL_TEXTURE0 + stage);
|
||||
// glBindTexture(GL_TEXTURE_2D, id_);
|
||||
GL_CHECK();
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
// Minimal procedural texture generator to generate some usual textures like circles and vignette textures.
|
||||
// "Gen" textures have filenames like this: "gen:256:256:vignette:0.1"
|
||||
//
|
||||
// These must be VERY VERY fast to not slow down loading. Could multicore this in the
|
||||
// future.
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "gfx/texture.h"
|
||||
|
||||
|
||||
uint8_t *generateTexture(const char *filename, int &bpp, int &w, int &h, bool &clamp) {
|
||||
char name_and_params[256];
|
||||
// security check :)
|
||||
if (strlen(filename) > 200)
|
||||
return 0;
|
||||
sscanf(filename, "gen:%i:%i:%s", &w, &h, name_and_params);
|
||||
|
||||
uint8_t *data;
|
||||
if (!strcmp(name_and_params, "vignette")) {
|
||||
bpp = 1;
|
||||
data = new uint8_t[w*h];
|
||||
for (int y = 0; y < h; ++y) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
float dx = (float)(x - w/2) / (w/2);
|
||||
float dy = (float)(y - h/2) / (h/2);
|
||||
float dist = sqrtf(dx * dx + dy * dy);
|
||||
dist /= 1.414f;
|
||||
float val = 1.0 - powf(dist, 1.4f);
|
||||
data[y*w + x] = val * 255;
|
||||
}
|
||||
}
|
||||
} else if (!strcmp(name_and_params, "circle")) {
|
||||
bpp = 1;
|
||||
// TODO
|
||||
data = new uint8_t[w*h];
|
||||
for (int y = 0; y < h; ++y) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
float dx = (float)(x - w/2) / (w/2);
|
||||
float dy = (float)(y - h/2) / (h/2);
|
||||
float dist = sqrtf(dx * dx + dy * dy);
|
||||
dist /= 1.414f;
|
||||
float val = 1.0 - powf(dist, 1.4f);
|
||||
data[y*w + x] = val * 255;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
data = NULL;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
// Minimal procedural texture generator to generate some useful but unnecessary-to-store textures like circles.
|
||||
// "Gen" textures have filenames like this: "gen:256:256:4444:vignette:0.1"
|
||||
|
||||
#include "gfx/texture.h"
|
||||
|
||||
uint8_t *generateTexture(const char *filename, int &bpp, int &w, int &h, bool &clamp);
|
@ -1,11 +1,9 @@
|
||||
set(SRCS
|
||||
draw_buffer.cpp
|
||||
draw_text.cpp
|
||||
fbo.cpp
|
||||
glsl_program.cpp
|
||||
gpu_features.cpp
|
||||
gl_state.cpp
|
||||
vertex_format.cpp)
|
||||
gl_state.cpp)
|
||||
|
||||
set(SRCS ${SRCS})
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
// "Immediate mode"-lookalike buffered drawing. Very fast way to draw 2D.
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/color.h"
|
||||
#include "base/colorutil.h"
|
||||
#include "gfx/gl_lost_manager.h"
|
||||
#include "gfx/texture_atlas.h"
|
||||
#include "math/geom2d.h"
|
||||
|
@ -1,71 +0,0 @@
|
||||
#include "base/logging.h"
|
||||
#include "gfx_es2/glsl_program.h"
|
||||
#include "gfx_es2/vertex_format.h"
|
||||
|
||||
static const GLuint formatLookup[16] = {
|
||||
GL_FLOAT,
|
||||
0, //GL_HALF_FLOAT_EXT,
|
||||
GL_UNSIGNED_SHORT,
|
||||
GL_UNSIGNED_BYTE,
|
||||
0, //GL_UNSIGNED_INT_10_10_10_2,
|
||||
0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
void SetVertexFormat(const GLSLProgram *program, uint32_t vertexFormat) {
|
||||
// First special case our favorites
|
||||
if (vertexFormat == (POS_FLOAT | NRM_FLOAT | UV0_FLOAT)) {
|
||||
const int vertexSize = 3*4 + 3*4 + 2*4;
|
||||
glUniform1i(program->sampler0, 0);
|
||||
glEnableVertexAttribArray(program->a_position);
|
||||
glEnableVertexAttribArray(program->a_normal);
|
||||
glEnableVertexAttribArray(program->a_texcoord0);
|
||||
glVertexAttribPointer(program->a_position, 3, GL_FLOAT, GL_FALSE, vertexSize, (void *)0);
|
||||
glVertexAttribPointer(program->a_normal, 3, GL_FLOAT, GL_FALSE, vertexSize, (void *)12);
|
||||
glVertexAttribPointer(program->a_texcoord0, 2, GL_FLOAT, GL_FALSE, vertexSize, (void *)24);
|
||||
return;
|
||||
}
|
||||
|
||||
// Then have generic code here.
|
||||
|
||||
|
||||
int vertexSize = 0;
|
||||
|
||||
FLOG("TODO: Write generic code.");
|
||||
|
||||
if (vertexFormat & UV0_MASK) {
|
||||
glUniform1i(program->sampler0, 0);
|
||||
}
|
||||
|
||||
glEnableVertexAttribArray(program->a_position);
|
||||
glVertexAttribPointer(program->a_position, 3, GL_FLOAT, GL_FALSE, vertexSize, (void *)0);
|
||||
if (vertexFormat & NRM_MASK) {
|
||||
glEnableVertexAttribArray(program->a_normal);
|
||||
glVertexAttribPointer(program->a_normal, 3, GL_FLOAT, GL_FALSE, vertexSize, (void *)12);
|
||||
}
|
||||
if (vertexFormat & UV0_MASK) {
|
||||
glEnableVertexAttribArray(program->a_texcoord0);
|
||||
glVertexAttribPointer(program->a_texcoord0, 2, GL_FLOAT, GL_FALSE, vertexSize, (void *)24);
|
||||
}
|
||||
if (vertexFormat & UV1_MASK) {
|
||||
glEnableVertexAttribArray(program->a_texcoord1);
|
||||
glVertexAttribPointer(program->a_texcoord1, 2, GL_FLOAT, GL_FALSE, vertexSize, (void *)24);
|
||||
}
|
||||
if (vertexFormat & RGBA_MASK) {
|
||||
glEnableVertexAttribArray(program->a_color);
|
||||
glVertexAttribPointer(program->a_color, 4, GL_FLOAT, GL_FALSE, vertexSize, (void *)28);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Save state so that we can get rid of this.
|
||||
void UnsetVertexFormat(const GLSLProgram *program, uint32_t vertexFormat) {
|
||||
glDisableVertexAttribArray(program->a_position);
|
||||
if (vertexFormat & NRM_MASK)
|
||||
glDisableVertexAttribArray(program->a_normal);
|
||||
if (vertexFormat & UV0_MASK)
|
||||
glDisableVertexAttribArray(program->a_texcoord0);
|
||||
if (vertexFormat & UV1_MASK)
|
||||
glDisableVertexAttribArray(program->a_texcoord1);
|
||||
if (vertexFormat & RGBA_MASK)
|
||||
glDisableVertexAttribArray(program->a_color);
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// TODO: Actually use for something :)
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
// Vertex format flags
|
||||
enum VtxFmt {
|
||||
POS_FLOAT = 1,
|
||||
POS_FLOAT16 = 2,
|
||||
POS_UINT16 = 3,
|
||||
POS_UINT8 = 4,
|
||||
POS_101010 = 5,
|
||||
|
||||
NRM_FLOAT = 1 << 4,
|
||||
NRM_FLOAT16 = 2 << 4,
|
||||
NRM_SINT16 = 3 << 4,
|
||||
NRM_UINT8 = 4 << 4,
|
||||
NRM_101010 = 5 << 4,
|
||||
|
||||
TANGENT_FLOAT = 1 << 8,
|
||||
//....
|
||||
|
||||
UV0_NONE = 1 << 12,
|
||||
UV0_FLOAT = 1 << 12,
|
||||
// ....
|
||||
UV1_NONE = 1 << 16,
|
||||
UV1_FLOAT = 1 << 16,
|
||||
|
||||
RGBA_NONE = 0 << 20,
|
||||
RGBA_FLOAT = 1 << 20,
|
||||
RGBA_FLOAT16 = 2 << 20,
|
||||
RGBA_UINT16 = 3 << 20,
|
||||
RGBA_UINT8 = 4 << 20,
|
||||
RGBA_101010 = 5 << 20,
|
||||
|
||||
POS_MASK = 0x0000000F,
|
||||
NRM_MASK = 0x000000F0,
|
||||
TANGENT_MASK = 0x00000F00,
|
||||
UV0_MASK = 0x0000F000,
|
||||
UV1_MASK = 0x000F0000,
|
||||
RGBA_MASK = 0x00F00000,
|
||||
|
||||
// Can add more here, such as a generic AUX or something. Don't know what to use it for though. Hardness for cloth sim?
|
||||
};
|
||||
|
||||
struct GLSLProgram;
|
||||
|
||||
// When calling this, the relevant vertex buffer must be bound to GL_ARRAY_BUFFER.
|
||||
void SetVertexFormat(const GLSLProgram *program, uint32_t format);
|
||||
void UnsetVertexFormat(const GLSLProgram *program, uint32_t format);
|
@ -2,7 +2,6 @@ set(SRCS
|
||||
lin/matrix4x4.cpp
|
||||
lin/vec3.cpp
|
||||
lin/quat.cpp
|
||||
lin/aabb.cpp
|
||||
curves.cpp
|
||||
math_util.cpp
|
||||
)
|
||||
|
@ -1,268 +0,0 @@
|
||||
#include "math/lin/aabb.h"
|
||||
#include "math/lin/ray.h"
|
||||
#include "math/lin/plane.h"
|
||||
|
||||
#define NUMDIM 3
|
||||
#define RIGHT 0
|
||||
#define LEFT 1
|
||||
#define MIDDLE 2
|
||||
|
||||
static const float flt_plus_inf = -logf(0); // let's keep C and C++ compilers happy.
|
||||
|
||||
AABB::AABB() : minB(0,0,0),maxB(0,0,0) {
|
||||
|
||||
}
|
||||
|
||||
void AABB::Add(const Vec3 &pt) {
|
||||
for (int i=0; i<3; i++)
|
||||
{
|
||||
if (pt[i] < minB[i])
|
||||
minB[i] = pt[i];
|
||||
if (pt[i] > maxB[i])
|
||||
maxB[i] = pt[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool AABB::Contains(const Vec3 &pt) const {
|
||||
for (int i=0; i<3; i++)
|
||||
{
|
||||
if (pt[i] < minB[i])
|
||||
return false;
|
||||
if (pt[i] > maxB[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool AABB::IntersectRay(const Ray &ray, float &tnear, float &tfar) const {
|
||||
float tNear=-flt_plus_inf, tFar=flt_plus_inf;
|
||||
//For each pair of planes P associated with X, Y, and Z do:
|
||||
//(example using X planes)
|
||||
for (int i=0; i<3; i++)
|
||||
{
|
||||
float min = minB[i];
|
||||
float max = maxB[i];
|
||||
|
||||
if (ray.dir[i] == 0.0f) //parallell! ARGH!
|
||||
if (ray.origin[i] < min || ray.origin[i] > max)
|
||||
return false;
|
||||
//Intersect with slab
|
||||
float T1 = (min - ray.origin[i]) * ray.invdir[i];
|
||||
float T2 = (max - ray.origin[i]) * ray.invdir[i];
|
||||
//Swap if necessary
|
||||
if (T1 > T2)
|
||||
{
|
||||
float temp=T1; T1=T2; T2=temp;
|
||||
}
|
||||
//Save closest/farthest hits
|
||||
if (T1 > tNear) tNear = T1;
|
||||
if (T2 < tFar) tFar = T2;
|
||||
}
|
||||
|
||||
if (tNear > tFar)
|
||||
return false; //missed the box
|
||||
else
|
||||
{
|
||||
if (tFar < 0)
|
||||
return false; //behind camera
|
||||
tnear = tNear;
|
||||
tfar = tFar;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Possible orientation of the splitting plane in the interior node of the kd-tree,
|
||||
// "No axis" denotes a leaf.
|
||||
enum Axes
|
||||
{
|
||||
Xaxis,
|
||||
Yaxis,
|
||||
Zaxis,
|
||||
Noaxis
|
||||
};
|
||||
|
||||
|
||||
|
||||
int AABB::GetShortestAxis() const
|
||||
{
|
||||
Vec3 delta = maxB-minB;
|
||||
if (delta.y<delta.x)
|
||||
{
|
||||
if (delta.z<delta.y)
|
||||
return 2;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (delta.z<delta.x)
|
||||
return 2;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int AABB::GetLongestAxis() const
|
||||
{
|
||||
Vec3 delta = maxB-minB;
|
||||
if (fabsf(delta.y) > fabsf(delta.x))
|
||||
{
|
||||
if (fabsf(delta.z) > fabsf(delta.y))
|
||||
return 2;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fabsf(delta.z) > fabsf(delta.x))
|
||||
return 2;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline void FINDMINMAX(float x0, float x1, float x2, float &min, float &max )
|
||||
{
|
||||
min = max = x0;
|
||||
if(x1<min)
|
||||
min=x1;
|
||||
if(x1>max)
|
||||
max=x1;
|
||||
if(x2<min)
|
||||
min=x2;
|
||||
if(x2>max)
|
||||
max=x2;
|
||||
}
|
||||
|
||||
// X-tests
|
||||
#define AXISTEST_X01( a, b, fa, fb ) \
|
||||
p0 = a * v0[1] - b * v0[2], p2 = a * v2[1] - b * v2[2]; \
|
||||
if (p0 < p2) { min = p0; max = p2;} else { min = p2; max = p0; } \
|
||||
rad = fa * a_BoxHalfsize[1] + fb * a_BoxHalfsize[2]; \
|
||||
if (min > rad || max < -rad) return 0;
|
||||
|
||||
#define AXISTEST_X2( a, b, fa, fb ) \
|
||||
p0 = a * v0[1] - b * v0[2], p1 = a * v1[1] - b * v1[2]; \
|
||||
if (p0 < p1) { min = p0; max = p1; } else { min = p1; max = p0;} \
|
||||
rad = fa * a_BoxHalfsize[1] + fb * a_BoxHalfsize[2]; \
|
||||
if(min>rad || max<-rad) return 0;
|
||||
// Y-tests
|
||||
#define AXISTEST_Y02( a, b, fa, fb ) \
|
||||
p0 = -a * v0[0] + b * v0[2], p2 = -a * v2[0] + b * v2[2]; \
|
||||
if(p0 < p2) { min = p0; max = p2; } else { min = p2; max = p0; } \
|
||||
rad = fa * a_BoxHalfsize[0] + fb * a_BoxHalfsize[2]; \
|
||||
if (min > rad || max < -rad) return 0;
|
||||
#define AXISTEST_Y1( a, b, fa, fb ) \
|
||||
p0 = -a * v0[0] + b * v0[2], p1 = -a * v1[0] + b * v1[2]; \
|
||||
if (p0 < p1) { min = p0; max = p1; } else { min = p1; max = p0; } \
|
||||
rad = fa * a_BoxHalfsize[0] + fb * a_BoxHalfsize[2]; \
|
||||
if (min > rad || max < -rad) return 0;
|
||||
// Z-tests
|
||||
#define AXISTEST_Z12( a, b, fa, fb ) \
|
||||
p1 = a * v1[0] - b * v1[1], p2 = a * v2[0] - b * v2[1]; \
|
||||
if(p2 < p1) { min = p2; max = p1; } else { min = p1; max = p2; } \
|
||||
rad = fa * a_BoxHalfsize[0] + fb * a_BoxHalfsize[1]; \
|
||||
if (min > rad || max < -rad) return 0;
|
||||
#define AXISTEST_Z0( a, b, fa, fb ) \
|
||||
p0 = a * v0[0] - b * v0[1], p1 = a * v1[0] - b * v1[1]; \
|
||||
if(p0 < p1) { min = p0; max = p1; } else { min = p1; max = p0; } \
|
||||
rad = fa * a_BoxHalfsize[0] + fb * a_BoxHalfsize[1]; \
|
||||
if (min > rad || max < -rad) return 0;
|
||||
|
||||
bool PlaneBoxOverlap(const Vec3& a_Normal, const Vec3& a_Vert, const Vec3& a_MaxBox )
|
||||
{
|
||||
Vec3 vmin, vmax;
|
||||
for (int q = 0; q < 3; q++)
|
||||
{
|
||||
float v = a_Vert[q];
|
||||
if (a_Normal[q] > 0.0f)
|
||||
{
|
||||
vmin[q] = -a_MaxBox[q] - v;
|
||||
vmax[q] = a_MaxBox[q] - v;
|
||||
}
|
||||
else
|
||||
{
|
||||
vmin[q] = a_MaxBox[q] - v;
|
||||
vmax[q] = -a_MaxBox[q] - v;
|
||||
}
|
||||
}
|
||||
if (( a_Normal * vmin) > 0.0f)
|
||||
return false;
|
||||
if (( a_Normal * vmax) >= 0.0f)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool AABB::IntersectsTriangle(const Vec3& a_V0, const Vec3& a_V1, const Vec3& a_V2 ) const
|
||||
{
|
||||
Vec3 a_BoxCentre = GetMidpoint();
|
||||
Vec3 a_BoxHalfsize = GetExtents() / 2.0f;
|
||||
Vec3 v0, v1, v2, normal, e0, e1, e2;
|
||||
float min, max, p0, p1, p2, rad, fex, fey, fez;
|
||||
v0 = a_V0 - a_BoxCentre;
|
||||
v1 = a_V1 - a_BoxCentre;
|
||||
v2 = a_V2 - a_BoxCentre;
|
||||
e0 = v1 - v0, e1 = v2 - v1, e2 = v0 - v2;
|
||||
fex = fabsf(e0[0]);
|
||||
fey = fabsf(e0[1]);
|
||||
fez = fabsf(e0[2]);
|
||||
AXISTEST_X01( e0[2], e0[1], fez, fey );
|
||||
AXISTEST_Y02( e0[2], e0[0], fez, fex );
|
||||
AXISTEST_Z12( e0[1], e0[0], fey, fex );
|
||||
fex = fabsf(e1[0]);
|
||||
fey = fabsf(e1[1]);
|
||||
fez = fabsf(e1[2]);
|
||||
AXISTEST_X01( e1[2], e1[1], fez, fey );
|
||||
AXISTEST_Y02( e1[2], e1[0], fez, fex );
|
||||
AXISTEST_Z0 ( e1[1], e1[0], fey, fex );
|
||||
fex = fabsf(e2[0]);
|
||||
fey = fabsf(e2[1]);
|
||||
fez = fabsf(e2[2]);
|
||||
AXISTEST_X2 ( e2[2], e2[1], fez, fey );
|
||||
AXISTEST_Y1 ( e2[2], e2[0], fez, fex );
|
||||
AXISTEST_Z12( e2[1], e2[0], fey, fex );
|
||||
FINDMINMAX( v0[0], v1[0], v2[0], min, max );
|
||||
if (min > a_BoxHalfsize[0] || max < -a_BoxHalfsize[0])
|
||||
return false;
|
||||
FINDMINMAX( v0[1], v1[1], v2[1], min, max );
|
||||
if (min > a_BoxHalfsize[1] || max < -a_BoxHalfsize[1])
|
||||
return false;
|
||||
FINDMINMAX( v0[2], v1[2], v2[2], min, max );
|
||||
if (min > a_BoxHalfsize[2] || max < -a_BoxHalfsize[2])
|
||||
return false;
|
||||
normal = e0 % e1;
|
||||
if (!PlaneBoxOverlap( normal, v0, a_BoxHalfsize ))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool AABB::BehindPlane(const Plane &plane) const {
|
||||
if (plane.Distance(minB) > 0)
|
||||
return false;
|
||||
if (plane.Distance(maxB) > 0)
|
||||
return false;
|
||||
|
||||
if (plane.Distance(maxB.x, minB.y, minB.z) > 0)
|
||||
return false;
|
||||
if (plane.Distance(maxB.x, maxB.y, minB.z) > 0)
|
||||
return false;
|
||||
if (plane.Distance(maxB.x, minB.y, maxB.z) > 0)
|
||||
return false;
|
||||
|
||||
if (plane.Distance(minB.x, maxB.y, minB.z) > 0)
|
||||
return false;
|
||||
if (plane.Distance(minB.x, minB.y, maxB.z) > 0)
|
||||
return false;
|
||||
if (plane.Distance(minB.x, maxB.y, maxB.z) > 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "math/lin/vec3.h"
|
||||
|
||||
struct Ray;
|
||||
class Plane;
|
||||
|
||||
struct AABB {
|
||||
Vec3 minB;
|
||||
int pad;
|
||||
Vec3 maxB;
|
||||
int pad2;
|
||||
|
||||
AABB();
|
||||
bool Contains(const Vec3 &pt) const;
|
||||
bool IntersectRay(const Ray &ray, float &tnear, float &tfar) const;
|
||||
|
||||
// Doesn't currently work.
|
||||
bool IntersectRay2(const Ray &ray, float &tnear, float &tfar) const;
|
||||
|
||||
bool IntersectsTriangle(const Vec3& a_V0, const Vec3& a_V1, const Vec3& a_V2) const;
|
||||
void Add(const Vec3 &pt);
|
||||
int GetShortestAxis() const;
|
||||
int GetLongestAxis() const;
|
||||
|
||||
float GetSize(int axis) const {
|
||||
return maxB[axis] - minB[axis];
|
||||
}
|
||||
float GetMidpoint(int axis) const {
|
||||
return (minB[axis] + maxB[axis]) / 2;
|
||||
}
|
||||
Vec3 GetMidpoint() const {
|
||||
return (minB + maxB) / 2;
|
||||
}
|
||||
Vec3 GetExtents() const {
|
||||
return maxB - minB;
|
||||
}
|
||||
|
||||
bool BehindPlane(const Plane &plane) const;
|
||||
};
|
@ -1,12 +0,0 @@
|
||||
set(SRCS
|
||||
midi_input.cpp
|
||||
)
|
||||
|
||||
set(SRCS ${SRCS})
|
||||
|
||||
add_library(midi STATIC ${SRCS})
|
||||
|
||||
if(UNIX)
|
||||
add_definitions(-fPIC)
|
||||
endif(UNIX)
|
||||
|
@ -1,90 +0,0 @@
|
||||
#ifdef _WIN32
|
||||
// Windows implementation.
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <MMSystem.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "midi/midi_input.h"
|
||||
#include "util/text/utf8.h"
|
||||
|
||||
std::vector<std::string> MidiInGetDevices() {
|
||||
int numDevs = midiInGetNumDevs();
|
||||
|
||||
std::vector<std::string> devices;
|
||||
for (int i = 0; i < numDevs; i++) {
|
||||
MIDIINCAPS caps;
|
||||
midiInGetDevCaps(i, &caps, sizeof(caps));
|
||||
devices.push_back(ConvertWStringToUTF8(caps.szPname));
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
|
||||
static void CALLBACK MidiCallback(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
|
||||
MidiListener *listener = (MidiListener*)dwInstance;
|
||||
uint8_t cmd[3] = {0};
|
||||
|
||||
switch (wMsg) {
|
||||
case MM_MIM_OPEN:
|
||||
ILOG("Got MIDI Open message");
|
||||
break;
|
||||
case MM_MIM_CLOSE:
|
||||
ILOG("Got MIDI Close message");
|
||||
break;
|
||||
case MM_MIM_DATA:
|
||||
cmd[0] = dwParam1 & 0xFF;
|
||||
cmd[1] = (dwParam1 >> 8) & 0xFF;
|
||||
cmd[2] = (dwParam1 >> 16) & 0xFF;
|
||||
// time = dwParam2 & 0xFFFF;
|
||||
ILOG("Got MIDI Data: %02x %02x %02x", cmd[0], cmd[1], cmd[2]);
|
||||
listener->midiEvent(cmd);
|
||||
break;
|
||||
default:
|
||||
WLOG("Got unexpected MIDI message: %08x", (uint32_t)wMsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MidiDevice MidiInStart(int deviceID, MidiListener *listener) {
|
||||
HMIDIIN hMidiIn;
|
||||
MMRESULT result = midiInOpen(&hMidiIn, deviceID, (DWORD_PTR)(&MidiCallback), (DWORD_PTR)listener, CALLBACK_FUNCTION);
|
||||
midiInStart(hMidiIn);
|
||||
return (MidiDevice)hMidiIn;
|
||||
}
|
||||
|
||||
void MidiInStop(MidiDevice device) {
|
||||
HMIDIIN hMidiIn = (HMIDIIN)device;
|
||||
midiInStop(hMidiIn);
|
||||
midiInClose(hMidiIn);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "midi/midi_input.h"
|
||||
|
||||
// Stubs for other platforms.
|
||||
|
||||
std::vector<std::string> MidiInGetDevices() {
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
MidiDevice MidiInStart(int deviceID, MidiListener *listener) {
|
||||
FLOG("Invalid MIDI device");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MidiInStop(MidiDevice device) {
|
||||
FLOG("Invalid MIDI device");
|
||||
}
|
||||
|
||||
#endif
|
@ -1,27 +0,0 @@
|
||||
// MIDI input.
|
||||
//
|
||||
// Currently, this is just a platform-clean wrapper around the Win32 MIDI input facilities.
|
||||
// Thus, it only supports Windows. Other platforms will get an empty list of midi in devices.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
typedef void *MidiDevice;
|
||||
|
||||
// Listeners inherit from this. Pass them into MidiInStart.
|
||||
class MidiListener
|
||||
{
|
||||
public:
|
||||
virtual ~MidiListener() {}
|
||||
virtual void midiEvent(const uint8_t *cmd) = 0;
|
||||
};
|
||||
|
||||
// Gets the names of the devices in a vector. The device identifier is the index in the vector.
|
||||
std::vector<std::string> MidiInGetDevices();
|
||||
|
||||
MidiDevice MidiInStart(int deviceID, MidiListener *listener);
|
||||
void MidiInStop(MidiDevice device);
|
@ -187,24 +187,16 @@
|
||||
<None Include="math\fast\fast_matrix_neon.S" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="audio\mixer.h" />
|
||||
<ClInclude Include="audio\wav_read.h" />
|
||||
<ClInclude Include="base\backtrace.h" />
|
||||
<ClInclude Include="base\basictypes.h" />
|
||||
<ClInclude Include="base\buffer.h" />
|
||||
<ClInclude Include="base\color.h" />
|
||||
<ClInclude Include="base\colorutil.h" />
|
||||
<ClInclude Include="base\compat.h" />
|
||||
<ClInclude Include="base\display.h" />
|
||||
<ClInclude Include="base\error_context.h" />
|
||||
<ClInclude Include="base\fastlist.h" />
|
||||
<ClInclude Include="base\functional.h" />
|
||||
<ClInclude Include="base\linked_ptr.h" />
|
||||
<ClInclude Include="base\logging.h" />
|
||||
<ClInclude Include="base\mutex.h" />
|
||||
<ClInclude Include="base\NativeApp.h" />
|
||||
<ClInclude Include="base\scoped_ptr.h" />
|
||||
<ClInclude Include="base\stats.h" />
|
||||
<ClInclude Include="base\stringutil.h" />
|
||||
<ClInclude Include="base\timeutil.h" />
|
||||
<ClInclude Include="data\compression.h" />
|
||||
@ -225,11 +217,9 @@
|
||||
<ClInclude Include="ext\libzip\zipint.h" />
|
||||
<ClInclude Include="ext\rg_etc1\rg_etc1.h" />
|
||||
<ClInclude Include="ext\sha1\sha1.h" />
|
||||
<ClInclude Include="ext\stb_vorbis\stb_vorbis.h" />
|
||||
<ClInclude Include="ext\vjson\block_allocator.h" />
|
||||
<ClInclude Include="ext\vjson\json.h" />
|
||||
<ClInclude Include="file\chunk_file.h" />
|
||||
<ClInclude Include="file\dialog.h" />
|
||||
<ClInclude Include="file\easy_file.h" />
|
||||
<ClInclude Include="file\fd_util.h" />
|
||||
<ClInclude Include="file\file_util.h" />
|
||||
@ -240,15 +230,12 @@
|
||||
<ClInclude Include="gfx\gl_common.h" />
|
||||
<ClInclude Include="gfx\gl_debug_log.h" />
|
||||
<ClInclude Include="gfx\gl_lost_manager.h" />
|
||||
<ClInclude Include="gfx\texture_gen.h" />
|
||||
<ClInclude Include="gfx\texture.h" />
|
||||
<ClInclude Include="gfx\texture_atlas.h" />
|
||||
<ClInclude Include="gfx_es2\draw_buffer.h" />
|
||||
<ClInclude Include="gfx_es2\draw_text.h" />
|
||||
<ClInclude Include="gfx_es2\gl3stub.h" />
|
||||
<ClInclude Include="gfx_es2\glsl_program.h" />
|
||||
<ClInclude Include="gfx_es2\gpu_features.h" />
|
||||
<ClInclude Include="gfx_es2\vertex_format.h" />
|
||||
<ClInclude Include="i18n\i18n.h" />
|
||||
<ClInclude Include="image\png_load.h" />
|
||||
<ClInclude Include="image\zim_load.h" />
|
||||
@ -260,7 +247,6 @@
|
||||
<ClInclude Include="math\curves.h" />
|
||||
<ClInclude Include="math\expression_parser.h" />
|
||||
<ClInclude Include="math\geom2d.h" />
|
||||
<ClInclude Include="math\lin\aabb.h" />
|
||||
<ClInclude Include="math\lin\matrix4x4.h" />
|
||||
<ClInclude Include="math\lin\plane.h" />
|
||||
<ClInclude Include="math\lin\quat.h" />
|
||||
@ -268,7 +254,6 @@
|
||||
<ClInclude Include="math\math_util.h" />
|
||||
<ClInclude Include="math\fast\fast_math.h" />
|
||||
<ClInclude Include="math\fast\fast_matrix.h" />
|
||||
<ClInclude Include="midi\midi_input.h" />
|
||||
<ClInclude Include="net\http_client.h" />
|
||||
<ClInclude Include="net\http_headers.h" />
|
||||
<ClInclude Include="net\http_server.h" />
|
||||
@ -289,8 +274,6 @@
|
||||
<ClInclude Include="ui\view.h" />
|
||||
<ClInclude Include="ui\viewgroup.h" />
|
||||
<ClInclude Include="ui\virtual_input.h" />
|
||||
<ClInclude Include="util\bits\bits.h" />
|
||||
<ClInclude Include="util\random\perlin.h" />
|
||||
<ClInclude Include="util\random\rng.h" />
|
||||
<ClInclude Include="util\text\parsers.h" />
|
||||
<ClInclude Include="util\text\shiftjis.h" />
|
||||
@ -298,8 +281,6 @@
|
||||
<ClInclude Include="util\text\utf8.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="audio\mixer.cpp" />
|
||||
<ClCompile Include="audio\wav_read.cpp" />
|
||||
<ClCompile Include="base\backtrace.cpp" />
|
||||
<ClCompile Include="base\BlackberryMain.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
@ -311,7 +292,6 @@
|
||||
<ClCompile Include="base\colorutil.cpp" />
|
||||
<ClCompile Include="base\compat.cpp" />
|
||||
<ClCompile Include="base\display.cpp" />
|
||||
<ClCompile Include="base\error_context.cpp" />
|
||||
<ClCompile Include="base\PCMain.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
@ -693,11 +673,9 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="ext\rg_etc1\rg_etc1.cpp" />
|
||||
<ClCompile Include="ext\sha1\sha1.cpp" />
|
||||
<ClCompile Include="ext\stb_vorbis\stb_vorbis.c" />
|
||||
<ClCompile Include="ext\vjson\block_allocator.cpp" />
|
||||
<ClCompile Include="ext\vjson\json.cpp" />
|
||||
<ClCompile Include="file\chunk_file.cpp" />
|
||||
<ClCompile Include="file\dialog.cpp" />
|
||||
<ClCompile Include="file\easy_file.cpp" />
|
||||
<ClCompile Include="file\fd_util.cpp" />
|
||||
<ClCompile Include="file\file_util.cpp" />
|
||||
@ -706,9 +684,7 @@
|
||||
<ClCompile Include="file\zip_read.cpp" />
|
||||
<ClCompile Include="gfx\gl_debug_log.cpp" />
|
||||
<ClCompile Include="gfx\gl_lost_manager.cpp" />
|
||||
<ClCompile Include="gfx\texture.cpp" />
|
||||
<ClCompile Include="gfx\texture_atlas.cpp" />
|
||||
<ClCompile Include="gfx\texture_gen.cpp" />
|
||||
<ClCompile Include="gfx_es2\draw_buffer.cpp" />
|
||||
<ClCompile Include="gfx_es2\draw_text.cpp" />
|
||||
<ClCompile Include="gfx_es2\gl3stub.c">
|
||||
@ -719,7 +695,6 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="gfx_es2\glsl_program.cpp" />
|
||||
<ClCompile Include="gfx_es2\gpu_features.cpp" />
|
||||
<ClCompile Include="gfx_es2\vertex_format.cpp" />
|
||||
<ClCompile Include="i18n\i18n.cpp" />
|
||||
<ClCompile Include="image\png_load.cpp" />
|
||||
<ClCompile Include="image\zim_load.cpp" />
|
||||
@ -729,7 +704,6 @@
|
||||
<ClCompile Include="json\json_writer.cpp" />
|
||||
<ClCompile Include="math\curves.cpp" />
|
||||
<ClCompile Include="math\expression_parser.cpp" />
|
||||
<ClCompile Include="math\lin\aabb.cpp" />
|
||||
<ClCompile Include="math\lin\matrix4x4.cpp" />
|
||||
<ClCompile Include="math\lin\plane.cpp" />
|
||||
<ClCompile Include="math\lin\quat.cpp" />
|
||||
@ -740,7 +714,6 @@
|
||||
<ClCompile Include="math\fast\fast_matrix_sse.c">
|
||||
<AssemblerOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AssemblyAndSourceCode</AssemblerOutput>
|
||||
</ClCompile>
|
||||
<ClCompile Include="midi\midi_input.cpp" />
|
||||
<ClCompile Include="net\http_client.cpp" />
|
||||
<ClCompile Include="net\http_headers.cpp" />
|
||||
<ClCompile Include="net\http_server.cpp" />
|
||||
@ -762,12 +735,7 @@
|
||||
<ClCompile Include="ui\view.cpp" />
|
||||
<ClCompile Include="ui\viewgroup.cpp" />
|
||||
<ClCompile Include="ui\virtual_input.cpp" />
|
||||
<ClCompile Include="util\bits\bits.cpp" />
|
||||
<ClCompile Include="util\hash\hash.cpp" />
|
||||
<ClCompile Include="util\random\perlin.cpp">
|
||||
<AssemblerOutput Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AssemblyAndSourceCode</AssemblerOutput>
|
||||
<AssemblerOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AssemblyAndSourceCode</AssemblerOutput>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\text\parsers.cpp" />
|
||||
<ClCompile Include="util\text\utf8.cpp" />
|
||||
</ItemGroup>
|
||||
|
@ -30,9 +30,6 @@
|
||||
<ClInclude Include="gfx\gl_debug_log.h">
|
||||
<Filter>gfx</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="base\color.h">
|
||||
<Filter>image</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="image\png_load.h">
|
||||
<Filter>image</Filter>
|
||||
</ClInclude>
|
||||
@ -57,12 +54,6 @@
|
||||
<ClInclude Include="gfx_es2\glsl_program.h">
|
||||
<Filter>gfx</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="audio\wav_read.h">
|
||||
<Filter>audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="audio\mixer.h">
|
||||
<Filter>audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="profiler\profiler.h">
|
||||
<Filter>profiler</Filter>
|
||||
</ClInclude>
|
||||
@ -84,12 +75,6 @@
|
||||
<ClInclude Include="base\basictypes.h">
|
||||
<Filter>base</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="base\scoped_ptr.h">
|
||||
<Filter>base</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="base\stats.h">
|
||||
<Filter>base</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gfx\gl_lost_manager.h">
|
||||
<Filter>gfx</Filter>
|
||||
</ClInclude>
|
||||
@ -102,12 +87,6 @@
|
||||
<ClInclude Include="base\timeutil.h">
|
||||
<Filter>base</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="base\error_context.h">
|
||||
<Filter>base</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gfx\texture.h">
|
||||
<Filter>gfx</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="input\gesture_detector.h">
|
||||
<Filter>input</Filter>
|
||||
</ClInclude>
|
||||
@ -120,9 +99,6 @@
|
||||
<ClInclude Include="base\colorutil.h">
|
||||
<Filter>base</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gfx\texture_gen.h">
|
||||
<Filter>gfx</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="json\json_writer.h">
|
||||
<Filter>json</Filter>
|
||||
</ClInclude>
|
||||
@ -132,9 +108,6 @@
|
||||
<ClInclude Include="file\path.h">
|
||||
<Filter>file</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gfx_es2\vertex_format.h">
|
||||
<Filter>gfx</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="base\NativeApp.h">
|
||||
<Filter>base</Filter>
|
||||
</ClInclude>
|
||||
@ -144,18 +117,9 @@
|
||||
<ClInclude Include="ui\ui.h">
|
||||
<Filter>ui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="midi\midi_input.h">
|
||||
<Filter>midi</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="file\dialog.h">
|
||||
<Filter>file</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="base\mutex.h">
|
||||
<Filter>base</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\bits\bits.h">
|
||||
<Filter>util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="data\listable.h">
|
||||
<Filter>data</Filter>
|
||||
</ClInclude>
|
||||
@ -183,18 +147,9 @@
|
||||
<ClInclude Include="base\backtrace.h">
|
||||
<Filter>base</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="base\fastlist.h">
|
||||
<Filter>base</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="math\lin\aabb.h">
|
||||
<Filter>math</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="math\lin\plane.h">
|
||||
<Filter>math</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\random\perlin.h">
|
||||
<Filter>util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\random\rng.h">
|
||||
<Filter>util</Filter>
|
||||
</ClInclude>
|
||||
@ -207,9 +162,6 @@
|
||||
<ClInclude Include="ui\ui_context.h">
|
||||
<Filter>ui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ext\stb_vorbis\stb_vorbis.h">
|
||||
<Filter>ext</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gfx_es2\gpu_features.h">
|
||||
<Filter>gfx</Filter>
|
||||
</ClInclude>
|
||||
@ -383,12 +335,6 @@
|
||||
<ClCompile Include="gfx_es2\glsl_program.cpp">
|
||||
<Filter>gfx</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="audio\wav_read.cpp">
|
||||
<Filter>audio</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="audio\mixer.cpp">
|
||||
<Filter>audio</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="profiler\profiler.cpp">
|
||||
<Filter>profiler</Filter>
|
||||
</ClCompile>
|
||||
@ -410,12 +356,6 @@
|
||||
<ClCompile Include="base\timeutil.cpp">
|
||||
<Filter>base</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base\error_context.cpp">
|
||||
<Filter>base</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gfx\texture.cpp">
|
||||
<Filter>gfx</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="input\gesture_detector.cpp">
|
||||
<Filter>input</Filter>
|
||||
</ClCompile>
|
||||
@ -425,9 +365,6 @@
|
||||
<ClCompile Include="base\colorutil.cpp">
|
||||
<Filter>base</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gfx\texture_gen.cpp">
|
||||
<Filter>gfx</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="json\json_writer.cpp">
|
||||
<Filter>json</Filter>
|
||||
</ClCompile>
|
||||
@ -437,24 +374,12 @@
|
||||
<ClCompile Include="file\path.cpp">
|
||||
<Filter>file</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gfx_es2\vertex_format.cpp">
|
||||
<Filter>gfx</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base\display.cpp">
|
||||
<Filter>base</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ui\ui.cpp">
|
||||
<Filter>ui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="midi\midi_input.cpp">
|
||||
<Filter>midi</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="file\dialog.cpp">
|
||||
<Filter>file</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\bits\bits.cpp">
|
||||
<Filter>util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="math\math_util.cpp">
|
||||
<Filter>math</Filter>
|
||||
</ClCompile>
|
||||
@ -479,15 +404,9 @@
|
||||
<ClCompile Include="base\backtrace.cpp">
|
||||
<Filter>base</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="math\lin\aabb.cpp">
|
||||
<Filter>math</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="math\lin\plane.cpp">
|
||||
<Filter>math</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\random\perlin.cpp">
|
||||
<Filter>util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ui\virtual_input.cpp">
|
||||
<Filter>ui</Filter>
|
||||
</ClCompile>
|
||||
@ -499,9 +418,6 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="base\BlackberryMain.cpp" />
|
||||
<ClCompile Include="base\PCMain.cpp" />
|
||||
<ClCompile Include="ext\stb_vorbis\stb_vorbis.c">
|
||||
<Filter>ext</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base\BlackberryMain.cpp">
|
||||
<Filter>base</Filter>
|
||||
</ClCompile>
|
||||
@ -835,9 +751,6 @@
|
||||
<Filter Include="ext">
|
||||
<UniqueIdentifier>{5c54b5e2-1bb2-4783-9df6-de4ff7105570}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="audio">
|
||||
<UniqueIdentifier>{4ea45f6c-de87-44a9-95b2-e1ec7e3601d0}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="profiler">
|
||||
<UniqueIdentifier>{c57b41dd-cc33-46ac-b479-19676455ae54}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@ -859,9 +772,6 @@
|
||||
<Filter Include="ui">
|
||||
<UniqueIdentifier>{d738c2d1-749d-4b60-b98f-f3da0bbbf40c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="midi">
|
||||
<UniqueIdentifier>{4710a9a2-d1fa-4920-ba1b-a7527902be53}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="util">
|
||||
<UniqueIdentifier>{e36ca540-863c-496b-b0f4-b1ece3e72feb}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "base/buffer.h"
|
||||
#include "file/fd_util.h"
|
||||
#include "net/http_server.h"
|
||||
#include "thread/executor.h"
|
||||
|
||||
namespace http {
|
||||
|
||||
|
@ -109,10 +109,8 @@ void ScreenManager::render() {
|
||||
iter--;
|
||||
iter--;
|
||||
Layer backback = *iter;
|
||||
UIDisableBegin();
|
||||
// Also shift to the right somehow...
|
||||
backback.screen->render();
|
||||
UIDisableEnd();
|
||||
stack_.back().screen->render();
|
||||
break;
|
||||
}
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "base/colorutil.h"
|
||||
#include "ui/ui.h"
|
||||
#include "ui/ui_context.h"
|
||||
#include "gfx/texture.h"
|
||||
#include "gfx/texture_atlas.h"
|
||||
#include "gfx_es2/draw_buffer.h"
|
||||
|
||||
@ -16,70 +15,10 @@
|
||||
DrawBuffer ui_draw2d;
|
||||
DrawBuffer ui_draw2d_front;
|
||||
|
||||
// This one, though, is OK.
|
||||
UIState uistate;
|
||||
UIState savedUistate;
|
||||
|
||||
// Theme.
|
||||
static const Atlas *themeAtlas;
|
||||
static UITheme theme;
|
||||
|
||||
void UIInit(const Atlas *atlas, const UITheme &ui_theme) {
|
||||
ui_draw2d.SetAtlas(atlas);
|
||||
ui_draw2d_front.SetAtlas(atlas);
|
||||
themeAtlas = atlas;
|
||||
theme = ui_theme;
|
||||
memset(&uistate, 0, sizeof(uistate));
|
||||
}
|
||||
|
||||
void UIDisableBegin()
|
||||
{
|
||||
savedUistate = uistate;
|
||||
memset(&uistate, 0, sizeof(uistate));
|
||||
}
|
||||
|
||||
void UIDisableEnd()
|
||||
{
|
||||
uistate = savedUistate;
|
||||
}
|
||||
|
||||
void UIUpdateMouse(int i, float x, float y, bool down) {
|
||||
if (down && !uistate.mousedown[i]) {
|
||||
uistate.mousepressed[i] = 1;
|
||||
uistate.mouseStartX[i] = x;
|
||||
uistate.mouseStartY[i] = y;
|
||||
} else {
|
||||
uistate.mousepressed[i] = 0;
|
||||
}
|
||||
uistate.mousex[i] = x;
|
||||
uistate.mousey[i] = y;
|
||||
uistate.mousedown[i] = down;
|
||||
|
||||
if (uistate.mousedown[i])
|
||||
uistate.mouseframesdown[i]++;
|
||||
else
|
||||
uistate.mouseframesdown[i] = 0;
|
||||
}
|
||||
|
||||
void UIReset() {
|
||||
memset(&uistate, 0, sizeof(uistate));
|
||||
}
|
||||
|
||||
bool UIRegionHit(int i, int x, int y, int w, int h, int margin) {
|
||||
// Input handling
|
||||
if (uistate.mousex[i] < x - margin ||
|
||||
uistate.mousey[i] < y - margin ||
|
||||
uistate.mousex[i] >= x + w + margin ||
|
||||
uistate.mousey[i] >= y + h + margin) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void UIBegin(Thin3DShaderSet *shaderSet) {
|
||||
for (int i = 0; i < MAX_POINTERS; i++)
|
||||
uistate.hotitem[i] = 0;
|
||||
ui_draw2d.Begin(shaderSet);
|
||||
ui_draw2d_front.Begin(shaderSet);
|
||||
}
|
||||
@ -90,520 +29,10 @@ void UIFlush() {
|
||||
}
|
||||
|
||||
void UIEnd() {
|
||||
for (int i = 0; i < MAX_POINTERS; i++) {
|
||||
if (uistate.mousedown[i] == 0) {
|
||||
uistate.activeitem[i] = 0;
|
||||
} else {
|
||||
if (uistate.activeitem[i] == 0) {
|
||||
uistate.activeitem[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
ui_draw2d.End();
|
||||
ui_draw2d_front.End();
|
||||
|
||||
if (uistate.ui_tick > 0)
|
||||
uistate.ui_tick--;
|
||||
ui_draw2d.Flush();
|
||||
ui_draw2d_front.Flush();
|
||||
}
|
||||
|
||||
void UIText(int x, int y, const char *text, uint32_t color, float scale, int align) {
|
||||
UIText(theme.uiFont, x, y, text, color, scale, align);
|
||||
}
|
||||
|
||||
void UIText(int font, int x, int y, const char *text, uint32_t color, float scale, int align) {
|
||||
ui_draw2d.SetFontScale(scale, scale);
|
||||
ui_draw2d.DrawTextShadow(font, text, x, y, color, align);
|
||||
ui_draw2d.SetFontScale(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
void UIText(int font, const LayoutManager &layout, const char *text, uint32_t color, float scale, int align)
|
||||
{
|
||||
ui_draw2d.SetFontScale(scale, scale);
|
||||
float w, h;
|
||||
ui_draw2d.MeasureText(font, text, &w, &h);
|
||||
float x, y;
|
||||
layout.GetPos(&w, &h, &x, &y);
|
||||
UIText(font, x, y, text, color, scale, 0);
|
||||
ui_draw2d.SetFontScale(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
int UIButton(int id, const LayoutManager &layout, float w, float h, const char *text, int button_align) {
|
||||
if (h == 0.0f)
|
||||
h = themeAtlas->images[theme.buttonImage].h;
|
||||
|
||||
float x, y;
|
||||
layout.GetPos(&w, &h, &x, &y);
|
||||
|
||||
if (button_align & ALIGN_HCENTER) x -= w / 2;
|
||||
if (button_align & ALIGN_VCENTER) y -= h / 2;
|
||||
if (button_align & ALIGN_RIGHT) x -= w;
|
||||
if (button_align & ALIGN_BOTTOM) y -= h;
|
||||
|
||||
int txOffset = 0;
|
||||
|
||||
int clicked = 0;
|
||||
for (int i = 0; i < MAX_POINTERS; i++) {
|
||||
// Check whether the button should be hot, use a generous margin for touch ease
|
||||
if (UIRegionHit(i, x, y, w, h, 8)) {
|
||||
uistate.hotitem[i] = id;
|
||||
if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) {
|
||||
uistate.activeitem[i] = id;
|
||||
}
|
||||
}
|
||||
|
||||
if (uistate.hotitem[i] == id) {
|
||||
if (uistate.activeitem[i] == id) {
|
||||
// Button is both 'hot' and 'active'
|
||||
txOffset = 2;
|
||||
} else {
|
||||
// Button is merely 'hot'
|
||||
}
|
||||
} else {
|
||||
// button is not hot, but it may be active
|
||||
}
|
||||
|
||||
// If button is hot and active, but mouse button is not
|
||||
// down, the user must have clicked the button.
|
||||
if (uistate.mousedown[i] == 0 &&
|
||||
uistate.hotitem[i] == id &&
|
||||
uistate.activeitem[i] == id) {
|
||||
clicked = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Render button
|
||||
|
||||
if (h == themeAtlas->images[theme.buttonImage].h)
|
||||
ui_draw2d.DrawImage2GridH((txOffset && theme.buttonSelected) ? theme.buttonSelected : theme.buttonImage, x, y, x + w);
|
||||
else
|
||||
ui_draw2d.DrawImage4Grid((txOffset && theme.buttonSelected) ? theme.buttonSelected : theme.buttonImage, x, y, x + w, y + h);
|
||||
ui_draw2d.DrawTextShadow(theme.uiFont, text, x + w/2, y + h/2 + txOffset, 0xFFFFFFFF, ALIGN_HCENTER | ALIGN_VCENTER);
|
||||
|
||||
uistate.lastwidget = id;
|
||||
return clicked;
|
||||
}
|
||||
|
||||
int UIImageButton(int id, const LayoutManager &layout, float w, int image, int button_align) {
|
||||
float h = 64;
|
||||
float x, y;
|
||||
layout.GetPos(&w, &h, &x, &y);
|
||||
|
||||
if (button_align & ALIGN_HCENTER) x -= w / 2;
|
||||
if (button_align & ALIGN_VCENTER) y -= h / 2;
|
||||
if (button_align & ALIGN_RIGHT) x -= w;
|
||||
if (button_align & ALIGN_BOTTOMRIGHT) y -= h;
|
||||
|
||||
int txOffset = 0;
|
||||
int clicked = 0;
|
||||
for (int i = 0; i < MAX_POINTERS; i++) {
|
||||
// Check whether the button should be hot, use a generous margin for touch ease
|
||||
if (UIRegionHit(i, x, y, w, h, 8)) {
|
||||
uistate.hotitem[i] = id;
|
||||
if (uistate.activeitem[i] == 0 && uistate.mousedown[i])
|
||||
uistate.activeitem[i] = id;
|
||||
}
|
||||
|
||||
if (uistate.hotitem[i] == id) {
|
||||
if (uistate.activeitem[i] == id) {
|
||||
// Button is both 'hot' and 'active'
|
||||
txOffset = 2;
|
||||
} else {
|
||||
// Button is merely 'hot'
|
||||
}
|
||||
} else {
|
||||
// button is not hot, but it may be active
|
||||
}
|
||||
|
||||
// If button is hot and active, but mouse button is not
|
||||
// down, the user must have clicked the button.
|
||||
if (uistate.mousedown[i] == 0 &&
|
||||
uistate.hotitem[i] == id &&
|
||||
uistate.activeitem[i] == id) {
|
||||
clicked = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Render button
|
||||
|
||||
ui_draw2d.DrawImage2GridH(theme.buttonImage, x, y, x + w);
|
||||
ui_draw2d.DrawImage(image, x + w/2, y + h/2 + txOffset, 1.0f, 0xFFFFFFFF, ALIGN_HCENTER | ALIGN_VCENTER);
|
||||
|
||||
uistate.lastwidget = id;
|
||||
return clicked;
|
||||
}
|
||||
|
||||
int UITextureButton(UIContext *ctx, int id, const LayoutManager &layout, float w, float h, Texture *texture, int button_align, uint32_t color, int drop_shadow) // uses current UI atlas for fetching images.
|
||||
{
|
||||
float x, y;
|
||||
layout.GetPos(&w, &h, &x, &y);
|
||||
|
||||
if (button_align & ALIGN_HCENTER) x -= w / 2;
|
||||
if (button_align & ALIGN_VCENTER) y -= h / 2;
|
||||
if (button_align & ALIGN_RIGHT) x -= w;
|
||||
if (button_align & ALIGN_BOTTOMRIGHT) y -= h;
|
||||
|
||||
int txOffset = 0;
|
||||
int clicked = 0;
|
||||
for (int i = 0; i < MAX_POINTERS; i++) {
|
||||
// Check whether the button should be hot, use a generous margin for touch ease
|
||||
if (UIRegionHit(i, x, y, w, h, 8)) {
|
||||
uistate.hotitem[i] = id;
|
||||
if (uistate.activeitem[i] == 0 && uistate.mousedown[i])
|
||||
uistate.activeitem[i] = id;
|
||||
}
|
||||
|
||||
if (uistate.hotitem[i] == id) {
|
||||
if (uistate.activeitem[i] == id) {
|
||||
// Button is both 'hot' and 'active'
|
||||
txOffset = 2;
|
||||
} else {
|
||||
// Button is merely 'hot'
|
||||
}
|
||||
} else {
|
||||
// button is not hot, but it may be active
|
||||
}
|
||||
|
||||
// If button is hot and active, but mouse button is not
|
||||
// down, the user must have clicked the button.
|
||||
if (uistate.mousedown[i] == 0 &&
|
||||
uistate.hotitem[i] == id &&
|
||||
uistate.activeitem[i] == id) {
|
||||
clicked = 1;
|
||||
}
|
||||
}
|
||||
if (texture) {
|
||||
float tw = texture->Width();
|
||||
float th = texture->Height();
|
||||
|
||||
// Adjust position so we don't stretch the image vertically or horizontally.
|
||||
// TODO: Add a param to specify fit? The below assumes it's never too wide.
|
||||
float nw = h * tw / th;
|
||||
x += (w - nw) / 2.0f;
|
||||
w = nw;
|
||||
}
|
||||
|
||||
// Render button
|
||||
int dropsize = 10;
|
||||
if (drop_shadow && texture)
|
||||
{
|
||||
if (txOffset) {
|
||||
dropsize = 3;
|
||||
y += txOffset * 2;
|
||||
}
|
||||
ui_draw2d.DrawImage4Grid(drop_shadow, x - dropsize, y, x+w + dropsize, y+h+dropsize*1.5,
|
||||
blackAlpha(0.5f), 1.0f);
|
||||
ui_draw2d.Flush(true);
|
||||
}
|
||||
|
||||
if (texture) {
|
||||
texture->Bind(0);
|
||||
} else {
|
||||
ui_draw2d.DrawImage2GridH(theme.buttonImage, x, y, x + w, color);
|
||||
ui_draw2d.Flush();
|
||||
|
||||
Texture::Unbind();
|
||||
}
|
||||
ui_draw2d.DrawTexRect(x, y, x+w, y+h, 0, 0, 1, 1, color);
|
||||
|
||||
ui_draw2d.Flush();
|
||||
ctx->RebindTexture();
|
||||
|
||||
uistate.lastwidget = id;
|
||||
return clicked;
|
||||
}
|
||||
|
||||
int UICheckBox(int id, int x, int y, const char *text, int align, bool *value) {
|
||||
#ifdef _WIN32
|
||||
const int h = 32;
|
||||
#else
|
||||
const int h = 48;
|
||||
#endif
|
||||
float tw, th;
|
||||
ui_draw2d.MeasureText(theme.uiFont, text, &tw, &th);
|
||||
int w = themeAtlas->images[theme.checkOn].w + UI_SPACE + tw;
|
||||
if (align & ALIGN_HCENTER) x -= w / 2;
|
||||
if (align & ALIGN_VCENTER) y -= h / 2;
|
||||
if (align & ALIGN_RIGHT) x -= w;
|
||||
if (align & ALIGN_BOTTOMRIGHT) y -= h;
|
||||
|
||||
int txOffset = 0;
|
||||
int clicked = 0;
|
||||
for (int i = 0; i < MAX_POINTERS; i++) {
|
||||
|
||||
// Check whether the button should be hot
|
||||
if (UIRegionHit(i, x, y, w, h, 8)) {
|
||||
uistate.hotitem[i] = id;
|
||||
if (uistate.activeitem[i] == 0 && uistate.mousedown[i])
|
||||
uistate.activeitem[i] = id;
|
||||
}
|
||||
|
||||
// Render button
|
||||
|
||||
if (uistate.hotitem[i] == id) {
|
||||
if (uistate.activeitem[i] == id) {
|
||||
// Button is both 'hot' and 'active'
|
||||
txOffset = 2;
|
||||
} else {
|
||||
// Button is merely 'hot'
|
||||
}
|
||||
} else {
|
||||
// button is not hot, but it may be active
|
||||
}
|
||||
// If button is hot and active, but mouse button is not
|
||||
// down, the user must have clicked the button.
|
||||
if (uistate.mousedown[i] == 0 &&
|
||||
uistate.hotitem[i] == id &&
|
||||
uistate.activeitem[i] == id) {
|
||||
*value = !(*value);
|
||||
clicked = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ui_draw2d.DrawImage((*value) ? theme.checkOn : theme.checkOff, x, y+h/2, 1.0f, 0xFFFFFFFF, ALIGN_LEFT | ALIGN_VCENTER);
|
||||
ui_draw2d.DrawTextShadow(theme.uiFont, text, x + themeAtlas->images[theme.checkOn].w + UI_SPACE, y + txOffset + h/2, 0xFFFFFFFF, ALIGN_LEFT | ALIGN_VCENTER);
|
||||
|
||||
|
||||
uistate.lastwidget = id;
|
||||
return clicked;
|
||||
}
|
||||
|
||||
void StringVectorListAdapter::drawItem(int item, int x, int y, int w, int h, bool selected) const
|
||||
{
|
||||
ui_draw2d.DrawImage2GridH(theme.buttonImage, x, y, x + w);
|
||||
ui_draw2d.DrawTextShadow(theme.uiFont, (*items_)[item].c_str(), x + UI_SPACE , y, 0xFFFFFFFF, ALIGN_LEFT | ALIGN_VCENTER);
|
||||
}
|
||||
|
||||
UIList::UIList()
|
||||
: scrollY(0.0f), startDragY(0.0f), dragFinger(-1), selected(-1) {
|
||||
movedDistanceX = 0.0f;
|
||||
movedDistanceY = 0.0f;
|
||||
scrolling = false;
|
||||
inertiaY = 0.0f;
|
||||
}
|
||||
|
||||
void UIList::pointerDown(int pointer, float x, float y) {
|
||||
// Instantly halt on pointerDown if inertia-scrolling
|
||||
scrolling = false;
|
||||
inertiaY = 0.0f;
|
||||
|
||||
startScrollY = scrollY;
|
||||
startDragY = y;
|
||||
movedDistanceX = 0.0f;
|
||||
movedDistanceY = 0.0f;
|
||||
}
|
||||
|
||||
const int holdFramesClick = 3;
|
||||
const int holdFramesScroll = 10;
|
||||
|
||||
void UIList::pointerMove(int pointer, float x, float y, bool inside) {
|
||||
float deltaX = x - lastX;
|
||||
float deltaY = y - lastY;
|
||||
movedDistanceY += fabsf(deltaY);
|
||||
movedDistanceX += fabsf(deltaX);
|
||||
|
||||
if (inertiaY <= 0.0f && deltaY > 0.0f) {
|
||||
inertiaY = -deltaY;
|
||||
} else if (inertiaY >= 0.0f && deltaY < 0.0f) {
|
||||
inertiaY = -deltaY;
|
||||
} else {
|
||||
inertiaY = 0.8 * inertiaY + 0.2 * -deltaY;
|
||||
}
|
||||
|
||||
const int deadzone = 30 * holdFramesScroll;
|
||||
if (inside && movedDistanceY * uistate.mouseframesdown[0] > deadzone && !scrolling) {
|
||||
scrolling = true;
|
||||
}
|
||||
}
|
||||
|
||||
void UIList::pointerUp(int pointer, float x, float y, bool inside) {
|
||||
// printf("PointerUp %f %f\n", x, y);
|
||||
}
|
||||
|
||||
int UIList::Do(int id, int x, int y, int w, int h, UIListAdapter *adapter) {
|
||||
int clicked = 0;
|
||||
|
||||
// Pointer and focus handling
|
||||
|
||||
// UIList only cares about the first pointer for simplicity.
|
||||
// Probably not much need to scroll one of these while dragging something
|
||||
// else.
|
||||
|
||||
// TODO: Abstract this stuff out into EmulatePointerEvents
|
||||
for (int i = 0; i < 1; i++) {
|
||||
// Check for hover
|
||||
bool isInside = false;
|
||||
if (UIRegionHit(i, x, y, w, h, 0)) {
|
||||
isInside = true;
|
||||
uistate.hotitem[i] = id;
|
||||
if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) {
|
||||
// Mousedown
|
||||
uistate.activeitem[i] = id;
|
||||
pointerDown(i, uistate.mousex[i], uistate.mousey[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (uistate.activeitem[i] == id) {
|
||||
// NOTE: won't work with multiple pointers
|
||||
if (uistate.mousex[i] != lastX || uistate.mousey[i] != lastY) {
|
||||
pointerMove(i, uistate.mousex[i], uistate.mousey[i], isInside);
|
||||
}
|
||||
}
|
||||
|
||||
// If button is hot and active, but mouse button is not
|
||||
// down, the user must have clicked a list item (unless after the last item).
|
||||
if (uistate.mousedown[i] == 0 &&
|
||||
uistate.activeitem[i] == id &&
|
||||
selected != -1) {
|
||||
if (uistate.hotitem[i] == id) {
|
||||
clicked = 1;
|
||||
}
|
||||
pointerUp(i, uistate.mousex[i], uistate.mousey[i], isInside);
|
||||
}
|
||||
}
|
||||
|
||||
int itemHeight = adapter->itemHeight(0);
|
||||
int numItems = (int)adapter->getCount();
|
||||
|
||||
// Cap total inertia
|
||||
if (inertiaY > 20) inertiaY = 20;
|
||||
if (inertiaY < -20) inertiaY = -20;
|
||||
|
||||
if (!uistate.mousedown[0]) {
|
||||
// Let it slide if the pointer is not down
|
||||
scrollY += inertiaY;
|
||||
} else if (scrolling /* && mouseY > y && mouseY < y + h*/ ) {
|
||||
// Pointer is down so stick to it
|
||||
scrollY = startScrollY - (uistate.mousey[0] - startDragY);
|
||||
}
|
||||
|
||||
// Inertia gradually trails off
|
||||
inertiaY *= 0.92f;
|
||||
if (scrolling && fabsf(inertiaY) < 0.001f)
|
||||
scrolling = false;
|
||||
|
||||
// Cap top and bottom softly.
|
||||
float maxScrollY = numItems * itemHeight - h;
|
||||
if (maxScrollY < 0.0f) maxScrollY = 0.0f;
|
||||
if (scrollY > maxScrollY) {
|
||||
scrollY -= 0.4f * (scrollY - maxScrollY);
|
||||
} else if (scrollY < 0.0f) {
|
||||
scrollY += 0.4f * -scrollY;
|
||||
}
|
||||
|
||||
lastX = uistate.mousex[0];
|
||||
lastY = uistate.mousey[0];
|
||||
uistate.lastwidget = id;
|
||||
|
||||
// Drawing and item hittesting
|
||||
|
||||
// render items
|
||||
for (int i = 0; i < numItems; i++) {
|
||||
int item_y = y + i * itemHeight - scrollY;
|
||||
|
||||
if (item_y >= y - itemHeight && item_y <= y + h) {
|
||||
for (int k = 0; k < 1; k++) { // MAX_POINTERS if we add back multitouch
|
||||
if (uistate.mousedown[k] &&
|
||||
uistate.mouseframesdown[k] >= holdFramesClick &&
|
||||
adapter->itemEnabled(i) &&
|
||||
!scrolling &&
|
||||
selected == -1 &&
|
||||
UIRegionHit(k, x, item_y, w, itemHeight, 0)) {
|
||||
selected = i;
|
||||
} else if (scrolling) {
|
||||
selected = -1;
|
||||
}
|
||||
}
|
||||
adapter->drawItem(i, x, item_y, w, itemHeight, i == selected);
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent scroll-clicks from registering
|
||||
if (selected == -1) clicked = 0;
|
||||
// Otherwise, no clicky.
|
||||
return clicked;
|
||||
}
|
||||
|
||||
/*
|
||||
struct SlideItem {
|
||||
const char *text;
|
||||
int image;
|
||||
uint32_t bgColor;
|
||||
};
|
||||
|
||||
struct SlideState
|
||||
{
|
||||
float scroll;
|
||||
|
||||
};
|
||||
|
||||
void UISlideChoice(int id, int y, const SlideItem *items, int numItems, SlideState *state)
|
||||
|
||||
}*/
|
||||
|
||||
// TODO
|
||||
int UIHSlider(int id, int x, int y, int w, int max, int *value) {
|
||||
// Calculate mouse cursor's relative y offset
|
||||
int xpos = ((256 - 16) * *value) / max;
|
||||
|
||||
for (int i = 0; i < MAX_POINTERS; i++) {
|
||||
// Check for hotness
|
||||
if (UIRegionHit(i, x+8, y+8, 16, 255, 0)) {
|
||||
uistate.hotitem[i] = id;
|
||||
if (uistate.activeitem[i] == 0 && uistate.mousedown[i])
|
||||
uistate.activeitem[i] = id;
|
||||
}
|
||||
|
||||
// Update widget value
|
||||
if (uistate.activeitem[i] == id) {
|
||||
int mousepos = uistate.mousey[i] - (y + 8);
|
||||
if (mousepos < 0) mousepos = 0;
|
||||
if (mousepos > 255) mousepos = 255;
|
||||
int v = (mousepos * max) / 255;
|
||||
if (v != *value) {
|
||||
*value = v;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Render the scrollbar
|
||||
ui_draw2d.Rect(x, y, 32, 256+16, 0x777777);
|
||||
|
||||
ui_draw2d.Rect(x+8+xpos, y+8, 16, 16, 0xffffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO
|
||||
int UIVSlider(int id, int x, int y, int h, int max, int *value) {
|
||||
// Calculate mouse cursor's relative y offset
|
||||
int ypos = ((256 - 16) * *value) / max;
|
||||
|
||||
// Check for hotness
|
||||
if (UIRegionHit(x+8, y+8, 16, 255, 0)) {
|
||||
uistate.hotitem = id;
|
||||
if (uistate.activeitem == 0 && uistate.mousedown)
|
||||
uistate.activeitem = id;
|
||||
}
|
||||
// Update widget value
|
||||
if (uistate.activeitem == id) {
|
||||
int mousepos = uistate.mousey - (y + 8);
|
||||
if (mousepos < 0) mousepos = 0;
|
||||
if (mousepos > 255) mousepos = 255;
|
||||
int v = (mousepos * max) / 255;
|
||||
if (v != *value) {
|
||||
*value = v;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// Render the scrollbar
|
||||
ui_draw2d.Rect(x, y, 32, 256+16, 0x777777);
|
||||
|
||||
ui_draw2d.Rect(x+8, y+8 + ypos, 16, 16, 0xffffff);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
@ -29,135 +29,8 @@
|
||||
#include "gfx_es2/draw_buffer.h"
|
||||
#include "input/input_state.h"
|
||||
|
||||
class Texture;
|
||||
class UIContext;
|
||||
|
||||
class LayoutManager {
|
||||
public:
|
||||
virtual void GetPos(float *w, float *h, float *x, float *y) const = 0;
|
||||
};
|
||||
|
||||
class Pos : public LayoutManager {
|
||||
public:
|
||||
Pos(float x, float y) : x_(x), y_(y) {}
|
||||
virtual void GetPos(float *w, float *h, float *x, float *y) const {
|
||||
*x = x_;
|
||||
*y = y_;
|
||||
}
|
||||
private:
|
||||
float x_;
|
||||
float y_;
|
||||
};
|
||||
|
||||
class HLinear : public LayoutManager {
|
||||
public:
|
||||
HLinear(float x, float y, float spacing = 2.0f) : x_(x), y_(y), spacing_(spacing) {}
|
||||
virtual void GetPos(float *w, float *h, float *x, float *y) const {
|
||||
*x = x_;
|
||||
*y = y_;
|
||||
x_ += *w + spacing_;
|
||||
}
|
||||
void Space(float x) {
|
||||
x_ += x;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable float x_;
|
||||
float y_;
|
||||
float spacing_;
|
||||
};
|
||||
|
||||
class VLinear : public LayoutManager {
|
||||
public:
|
||||
VLinear(float x, float y, float spacing = 2.0f) : x_(x), y_(y), spacing_(spacing) {}
|
||||
virtual void GetPos(float *w, float *h, float *x, float *y) const {
|
||||
*x = x_;
|
||||
*y = y_;
|
||||
y_ += *h + spacing_;
|
||||
}
|
||||
|
||||
private:
|
||||
float x_;
|
||||
mutable float y_;
|
||||
float spacing_;
|
||||
};
|
||||
|
||||
class HGrid : public LayoutManager {
|
||||
public:
|
||||
HGrid(float x, float y, float xMax, float xSpacing = 2.0f, float ySpacing = 2.0f)
|
||||
: x_(x), y_(y), xInit_(x), xMax_(xMax), xSpacing_(xSpacing), ySpacing_(ySpacing) {}
|
||||
virtual void GetPos(float *w, float *h, float *x, float *y) const {
|
||||
*x = x_;
|
||||
*y = y_;
|
||||
x_ += *w + xSpacing_;
|
||||
if (x_ >= xMax_) {
|
||||
x_ = xInit_;
|
||||
y_ += *h + ySpacing_;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
mutable float x_;
|
||||
mutable float y_;
|
||||
float xInit_;
|
||||
float xMax_;
|
||||
float xSpacing_;
|
||||
float ySpacing_;
|
||||
};
|
||||
|
||||
class VGrid : public LayoutManager {
|
||||
public:
|
||||
VGrid(float x, float y, float yMax, float xSpacing = 2.0f, float ySpacing = 2.0f)
|
||||
: x_(x), y_(y), yInit_(y), yMax_(yMax), xSpacing_(xSpacing), ySpacing_(ySpacing) {}
|
||||
virtual void GetPos(float *w, float *h, float *x, float *y) const {
|
||||
*x = x_;
|
||||
*y = y_;
|
||||
y_ += *h + ySpacing_;
|
||||
if (y_ + *h >= yMax_) {
|
||||
x_ += *w + xSpacing_;
|
||||
y_ = yInit_;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
mutable float x_;
|
||||
mutable float y_;
|
||||
float yInit_;
|
||||
float yMax_;
|
||||
float xSpacing_;
|
||||
float ySpacing_;
|
||||
};
|
||||
|
||||
// "Mouse" out of habit, applies just as well to touch events.
|
||||
// TODO: Change to "pointer"
|
||||
// This struct is zeroed on init, so should be valid at that state.
|
||||
// Never inherit from this.
|
||||
struct UIState {
|
||||
int mousex[MAX_POINTERS];
|
||||
int mousey[MAX_POINTERS];
|
||||
bool mousedown[MAX_POINTERS];
|
||||
bool mousepressed[MAX_POINTERS];
|
||||
short mouseframesdown[MAX_POINTERS];
|
||||
|
||||
int mouseStartX[MAX_POINTERS];
|
||||
int mouseStartY[MAX_POINTERS];
|
||||
|
||||
int hotitem[MAX_POINTERS];
|
||||
int activeitem[MAX_POINTERS];
|
||||
|
||||
// keyboard focus, not currently used
|
||||
int kbdwidget;
|
||||
int lastwidget;
|
||||
|
||||
int ui_tick;
|
||||
|
||||
// deprecated: tempfloat
|
||||
float tempfloat;
|
||||
};
|
||||
|
||||
// This needs to be extern so that additional UI controls can be developed outside this file.
|
||||
extern UIState uistate;
|
||||
|
||||
struct Atlas;
|
||||
|
||||
// This is the drawbuffer used for UI. Remember to flush it at the end of the frame.
|
||||
@ -165,41 +38,7 @@ struct Atlas;
|
||||
extern DrawBuffer ui_draw2d;
|
||||
extern DrawBuffer ui_draw2d_front; // for things that need to be on top of the rest
|
||||
|
||||
struct UITheme {
|
||||
int uiFont;
|
||||
int uiFontSmall;
|
||||
int uiFontSmaller;
|
||||
int buttonImage;
|
||||
int buttonSelected;
|
||||
int checkOn;
|
||||
int checkOff;
|
||||
};
|
||||
|
||||
// The atlas needs to stick around, the theme is copied.
|
||||
void UIInit(const Atlas *atlas, const UITheme &theme);
|
||||
|
||||
// Between these, UI components won't see pointer events.
|
||||
void UIDisableBegin();
|
||||
void UIDisableEnd();
|
||||
|
||||
// Just lets you retrieve the theme that was passed into UIInit, for your own controls for example.
|
||||
UITheme &UIGetTheme();
|
||||
|
||||
// TODO: These don't really belong here.
|
||||
const int UI_SPACE = 32;
|
||||
const int SMALL_BUTTON_WIDTH = 128;
|
||||
const int LARGE_BUTTON_WIDTH = 192;
|
||||
const int BUTTON_HEIGHT = 72;
|
||||
|
||||
struct SlideItem {
|
||||
const char *text;
|
||||
int image;
|
||||
uint32_t bgColor;
|
||||
};
|
||||
|
||||
struct UISlideState {
|
||||
float scroll;
|
||||
};
|
||||
|
||||
// Implement this interface to style your lists
|
||||
class UIListAdapter {
|
||||
@ -221,9 +60,6 @@ private:
|
||||
};
|
||||
|
||||
|
||||
// Utility functions, useful when implementing your own controls
|
||||
bool UIRegionHit(int pointerId, int x, int y, int w, int h, int margin);
|
||||
|
||||
// Call at start of frame
|
||||
void UIBegin(Thin3DShaderSet *shaderSet);
|
||||
|
||||
@ -232,69 +68,3 @@ void UIBegin(Thin3DShaderSet *shaderSet);
|
||||
void UIEnd();
|
||||
void UIFlush();
|
||||
|
||||
void UIUpdateMouse(int i, float x, float y, bool down);
|
||||
|
||||
// Call when you switch screens
|
||||
void UIReset();
|
||||
|
||||
// Returns 1 if clicked
|
||||
int UIButton(int id, const LayoutManager &layout, float w, float h, const char *text, int button_align);
|
||||
int UIImageButton(int id, const LayoutManager &layout, float w, int image_id, int button_align); // uses current UI atlas for fetching images.
|
||||
int UITextureButton(UIContext *ctx, int id, const LayoutManager &layout, float w, float h, Texture *texture, int button_align, uint32_t color, int drop_shadow=0); // uses current UI atlas for fetching images.
|
||||
// Returns 1 if clicked, puts the value in *value (where it also gets the current state).
|
||||
int UICheckBox(int id, int x, int y, const char *text, int align, bool *value);
|
||||
|
||||
// Vertical slider. Not yet working.
|
||||
// int UIVSlider(int id, int x, int y, int h, int max, int *value);
|
||||
|
||||
// Horizontal slider. Not yet working.
|
||||
int UIHSlider(int id, int x, int y, int w, int max, int *value);
|
||||
|
||||
// Draws static text, that does not participate in any focusing scheme etc, it just is.
|
||||
void UIText(int font, int x, int y, const char *text, uint32_t color, float scale = 1.0f, int align = ALIGN_TOPLEFT);
|
||||
void UIText(int x, int y, const char *text, uint32_t color, float scale = 1.0f, int align = ALIGN_TOPLEFT);
|
||||
void UIText(int font, const LayoutManager &layout, const char *text, uint32_t color, float scale = 1.0f, int align = ALIGN_TOPLEFT);
|
||||
|
||||
// Slide choice, like the Angry Birds level selector. Not yet working.
|
||||
void UISlideChoice(int id, int y, const SlideItem *items, int numItems, UISlideState *state);
|
||||
|
||||
|
||||
class UIList {
|
||||
public:
|
||||
UIList();
|
||||
|
||||
bool scrolling;
|
||||
int activePointer;
|
||||
float startScrollY;
|
||||
float scrollY;
|
||||
float lastX;
|
||||
float lastY;
|
||||
float startDragY;
|
||||
float movedDistanceX;
|
||||
float movedDistanceY;
|
||||
float inertiaY;
|
||||
|
||||
int dragFinger;
|
||||
int selected;
|
||||
// List view.
|
||||
// return -1 = no selection
|
||||
int Do(int id, int x, int y, int w, int h, UIListAdapter *adapter);
|
||||
|
||||
// Call this when the content has changed, to reset scroll position etc.
|
||||
void contentChanged() {
|
||||
scrollY = 0.0f;
|
||||
inertiaY = 0.0f;
|
||||
}
|
||||
|
||||
void scrollRelative(float delta) {
|
||||
scrollY += delta;
|
||||
}
|
||||
private:
|
||||
// TODO: Migrate to using these directly.
|
||||
void pointerDown(int pointer, float x, float y);
|
||||
void pointerUp(int pointer, float x, float y, bool inside);
|
||||
void pointerMove(int pointer, float x, float y, bool inside);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(UIList);
|
||||
};
|
||||
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "input/input_state.h"
|
||||
#include "input/keycodes.h"
|
||||
#include "gfx_es2/draw_buffer.h"
|
||||
#include "gfx/texture.h"
|
||||
#include "gfx/texture_atlas.h"
|
||||
#include "util/text/utf8.h"
|
||||
#include "ui/ui.h"
|
||||
@ -573,28 +572,6 @@ void ImageView::Draw(UIContext &dc) {
|
||||
dc.Draw()->DrawImage(atlasImage_, bounds_.x, bounds_.y, scale, 0xFFFFFFFF, ALIGN_TOPLEFT);
|
||||
}
|
||||
|
||||
void TextureView::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
// TODO: involve sizemode
|
||||
if (texture_) {
|
||||
w = (float)texture_->Width();
|
||||
h = (float)texture_->Height();
|
||||
} else {
|
||||
w = 16;
|
||||
h = 16;
|
||||
}
|
||||
}
|
||||
|
||||
void TextureView::Draw(UIContext &dc) {
|
||||
// TODO: involve sizemode
|
||||
if (texture_) {
|
||||
dc.Flush();
|
||||
texture_->Bind(0);
|
||||
dc.Draw()->Rect(bounds_.x, bounds_.y, bounds_.w, bounds_.h, color_);
|
||||
dc.Flush();
|
||||
dc.RebindTexture();
|
||||
}
|
||||
}
|
||||
|
||||
void Thin3DTextureView::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
// TODO: involve sizemode
|
||||
if (texture_) {
|
||||
|
@ -11,12 +11,12 @@
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/functional.h"
|
||||
#include "base/mutex.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/scoped_ptr.h"
|
||||
#include "gfx/texture_atlas.h"
|
||||
#include "math/lin/matrix4x4.h"
|
||||
#include "math/math_util.h"
|
||||
@ -24,6 +24,10 @@
|
||||
|
||||
#undef small
|
||||
|
||||
#ifdef __SYMBIAN32__
|
||||
#define unique_ptr auto_ptr
|
||||
#endif
|
||||
|
||||
struct KeyInput;
|
||||
struct TouchInput;
|
||||
struct AxisInput;
|
||||
@ -365,7 +369,7 @@ public:
|
||||
|
||||
protected:
|
||||
// Inputs to layout
|
||||
scoped_ptr<LayoutParams> layoutParams_;
|
||||
std::unique_ptr<LayoutParams> layoutParams_;
|
||||
|
||||
std::string tag_;
|
||||
Visibility visibility_;
|
||||
@ -377,7 +381,7 @@ protected:
|
||||
// Outputs of layout. X/Y are absolute screen coordinates, hierarchy is "gone" here.
|
||||
Bounds bounds_;
|
||||
|
||||
scoped_ptr<Matrix4x4> transform_;
|
||||
std::unique_ptr<Matrix4x4> transform_;
|
||||
|
||||
private:
|
||||
bool *enabledPtr_;
|
||||
@ -741,25 +745,6 @@ private:
|
||||
ImageSizeMode sizeMode_;
|
||||
};
|
||||
|
||||
// TextureView takes a texture that is assumed to be alive during the lifetime
|
||||
// of the view.
|
||||
class TextureView : public InertView {
|
||||
public:
|
||||
TextureView(Texture *texture, ImageSizeMode sizeMode, LayoutParams *layoutParams = 0)
|
||||
: InertView(layoutParams), texture_(texture), sizeMode_(sizeMode) {}
|
||||
|
||||
void GetContentDimensions(const UIContext &dc, float &w, float &h) const override;
|
||||
void Draw(UIContext &dc) override;
|
||||
|
||||
void SetTexture(Texture *texture) { texture_ = texture; }
|
||||
void SetColor(uint32_t color) { color_ = color; }
|
||||
|
||||
private:
|
||||
Texture *texture_;
|
||||
uint32_t color_;
|
||||
ImageSizeMode sizeMode_;
|
||||
};
|
||||
|
||||
// TextureView takes a texture that is assumed to be alive during the lifetime
|
||||
// of the view.
|
||||
class Thin3DTextureView : public InertView {
|
||||
|
@ -1,7 +1,5 @@
|
||||
set(SRCS
|
||||
bits/bits.cpp
|
||||
bits/varint.cpp
|
||||
random/perlin.cpp
|
||||
hash/hash.cpp
|
||||
text/utf8.cpp
|
||||
)
|
||||
|
@ -1,40 +0,0 @@
|
||||
#include "util/bits/bits.h"
|
||||
|
||||
namespace bits {
|
||||
|
||||
// See http://graphics.stanford.edu/~seander/bithacks.html
|
||||
|
||||
static const unsigned char BitsSetTable256[] = {
|
||||
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
|
||||
};
|
||||
|
||||
int CountBits8(uint8_t v) {
|
||||
return BitsSetTable256[v];
|
||||
}
|
||||
|
||||
int CountBits16(uint16_t v) {
|
||||
return BitsSetTable256[v & 0xFF] + BitsSetTable256[v >> 8];
|
||||
}
|
||||
|
||||
int CountBits32(uint32_t v) {
|
||||
v = v - ((v >> 1) & 0x55555555); // reuse input as temporary
|
||||
v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp
|
||||
return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count
|
||||
}
|
||||
|
||||
} // namespace bits
|
@ -1,65 +0,0 @@
|
||||
#ifndef _UTIL_BITS_BITS
|
||||
#define _UTIL_BITS_BITS
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
namespace bits {
|
||||
|
||||
int CountBits8(uint8_t v);
|
||||
int CountBits16(uint16_t v);
|
||||
int CountBits32(uint32_t v);
|
||||
|
||||
// where mask is 0, the result is a.
|
||||
// where mask is 1, the result is b.
|
||||
inline uint32_t MixBits(uint32_t a, uint32_t b, uint32_t mask) {
|
||||
return a ^ ((a ^ b) & mask);
|
||||
}
|
||||
|
||||
inline uint32_t ComputeParity(uint32_t v) {
|
||||
v ^= v >> 16;
|
||||
v ^= v >> 8;
|
||||
v ^= v >> 4;
|
||||
v &= 0xf;
|
||||
return (0x6996 >> v) & 1;
|
||||
}
|
||||
|
||||
} // namespace bits
|
||||
|
||||
#ifndef _MSC_VER
|
||||
|
||||
// These are built-ins in MSVC, let's define them for other OS:es as well.
|
||||
|
||||
inline uint32_t _rotl(uint32_t val, int shift) {
|
||||
return (val << shift) | (val >> (31 - shift));
|
||||
}
|
||||
|
||||
inline uint32_t _rotr(uint32_t val, int shift) {
|
||||
return (val << shift) | (val >> (31 - shift));
|
||||
}
|
||||
|
||||
/*
|
||||
template <int SZ>
|
||||
class BitArray {
|
||||
public:
|
||||
BitArray() {
|
||||
memset(data, 0, sizeof(data));
|
||||
}
|
||||
|
||||
BitArray And(const BitArray &other) {
|
||||
BitArray<SZ> retVal;
|
||||
for (int i = 0; i < DATACOUNT; i++) {
|
||||
retVal.data[i] = data[i] & other.data[i];
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 data[(SZ + 31) / 32];
|
||||
enum {
|
||||
DATACOUNT = (SZ + 31) / 32;
|
||||
};
|
||||
};
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,27 +0,0 @@
|
||||
#ifndef _UTIL_BITS_HAMMING
|
||||
#define _UTIL_BITS_HAMMING
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
inline int Hamming(const std::string &a, const std::string &b) {
|
||||
CHECK_EQ(a.size(), b.size());
|
||||
int hamming = 0;
|
||||
for (size_t i = 0; i < a.size(); i++)
|
||||
hamming += a[i] == b[i];
|
||||
return hamming;
|
||||
}
|
||||
|
||||
inline int Hamming4(const std::string &a, const std::string &b) {
|
||||
CHECK_EQ(a.size(), b.size());
|
||||
int hamming = 0;
|
||||
const uint32 *au = (const uint32 *)a.data();
|
||||
const uint32 *bu = (const uint32 *)b.data();
|
||||
for (size_t i = 0; i < a.size() / 4; i++)
|
||||
hamming += au[i] == bu[i];
|
||||
return hamming * 4;
|
||||
}
|
||||
|
||||
|
||||
#endif // _UTIL_BITS_HAMMING
|
@ -1,35 +0,0 @@
|
||||
#include "util/bits/varint.h"
|
||||
|
||||
namespace varint {
|
||||
|
||||
void Encode32(uint32_t value, char **dest) {
|
||||
// Simple varint
|
||||
char *p = *dest;
|
||||
while (value > 127) {
|
||||
*p++ = (value & 127);
|
||||
value >>= 7;
|
||||
}
|
||||
*p++ = value | 0x80;
|
||||
*dest = p;
|
||||
}
|
||||
|
||||
uint32_t Decode32(const char **ptr) {
|
||||
uint32_t value = 0;
|
||||
const char *p = *ptr;
|
||||
while (true) {
|
||||
uint8_t b = *p++;
|
||||
if (b & 0x80) {
|
||||
*ptr = p;
|
||||
return value | (b & 0x7F);
|
||||
} else {
|
||||
value |= *p++;
|
||||
value <<= 7;
|
||||
}
|
||||
}
|
||||
*ptr = p;
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace varint
|
||||
|
||||
|
@ -1,13 +0,0 @@
|
||||
#ifndef _UTIL_BITS_VARINT
|
||||
#define _UTIL_BITS_VARINT
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
namespace varint {
|
||||
|
||||
void Encode32(uint32_t value, char **dest);
|
||||
uint32_t Decode32(const char **ptr);
|
||||
|
||||
} // namespace varint
|
||||
|
||||
#endif // _UTIL_BITS_VARINT
|
@ -1,72 +0,0 @@
|
||||
#include "util/random/perlin.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
// This should go in the const section of the binary.
|
||||
static const int p[512] = {
|
||||
151,160,137,91,90,15,
|
||||
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
|
||||
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
|
||||
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
|
||||
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
|
||||
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
|
||||
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
|
||||
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
|
||||
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
|
||||
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
|
||||
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
|
||||
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
|
||||
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,
|
||||
151,160,137,91,90,15,
|
||||
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
|
||||
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
|
||||
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
|
||||
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
|
||||
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
|
||||
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
|
||||
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
|
||||
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
|
||||
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
|
||||
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
|
||||
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
|
||||
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,
|
||||
};
|
||||
|
||||
inline float fade(float t) {
|
||||
return t * t * t * (t * (t * 6 - 15) + 10);
|
||||
}
|
||||
|
||||
inline float lerp(float t, float a, float b) {
|
||||
return a + t * (b - a);
|
||||
}
|
||||
|
||||
inline float grad(int hash, float x, float y, float z) {
|
||||
int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE
|
||||
float u = h < 8 ? x : y; // INTO 12 GRADIENT DIRECTIONS.
|
||||
float v = h < 4 ? y : (h == 12 || h == 14 ? x : z);
|
||||
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
|
||||
}
|
||||
|
||||
float Noise(double iz, double iy, double ix) {
|
||||
double fx = floor(ix), fy = floor(iy), fz = floor(iz);
|
||||
int X = (int)fx & 255, // FIND UNIT CUBE THAT
|
||||
Y = (int)fy & 255, // CONTAINS POINT.
|
||||
Z = (int)fz & 255;
|
||||
float x = (float)(ix - fx); // FIND RELATIVE X,Y,Z
|
||||
float y = (float)(iy - fy); // OF POINT IN CUBE.
|
||||
float z = (float)(iz - fz);
|
||||
float u = fade(x); // COMPUTE FADE CURVES
|
||||
float v = fade(y); // FOR EACH OF X,Y,Z.
|
||||
float w = fade(z);
|
||||
int A = p[X ]+Y, B = p[X+1]+Y;
|
||||
int AA = p[A]+Z, AB = p[A+1]+Z; // HASH COORDINATES OF
|
||||
int BA = p[B]+Z, BB = p[B+1]+Z; // THE 8 CUBE CORNERS,
|
||||
return lerp(w, lerp(v, lerp(u, grad(p[AA ], x , y , z ), // AND ADD
|
||||
grad(p[BA ], x-1, y , z )), // BLENDED
|
||||
lerp(u, grad(p[AB ], x , y-1, z ), // RESULTS
|
||||
grad(p[BB ], x-1, y-1, z ))), // FROM 8
|
||||
lerp(v, lerp(u, grad(p[AA+1], x , y , z-1 ), // CORNERS
|
||||
grad(p[BA+1], x-1, y , z-1 )), // OF CUBE
|
||||
lerp(u, grad(p[AB+1], x , y-1, z-1 ),
|
||||
grad(p[BB+1], x-1, y-1, z-1 ))));
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Implementation of "Improved Noise"
|
||||
// http://mrl.nyu.edu/~perlin/noise/
|
||||
// doubles are only used at the very start, not a big performance worry
|
||||
float Noise(double x, double y, double z);
|
Loading…
Reference in New Issue
Block a user