diff --git a/src/core.h b/src/core.h index aa10ddd..4068689 100644 --- a/src/core.h +++ b/src/core.h @@ -43,6 +43,38 @@ #define glProgramBinary glProgramBinaryOES #define GL_PROGRAM_BINARY_LENGTH GL_PROGRAM_BINARY_LENGTH_OES +#elif __RPI__ + #define MOBILE + #include + #include + #include + #include + + #define GL_CLAMP_TO_BORDER 0x812D + #define GL_TEXTURE_BORDER_COLOR 0x1004 + + #define GL_TEXTURE_COMPARE_MODE 0x884C + #define GL_TEXTURE_COMPARE_FUNC 0x884D + #define GL_COMPARE_REF_TO_TEXTURE 0x884E + + #undef GL_RGBA32F + #undef GL_RGBA16F + #undef GL_HALF_FLOAT + + #define GL_RGBA32F GL_RGBA + #define GL_RGBA16F GL_RGBA + #define GL_HALF_FLOAT GL_HALF_FLOAT_OES + + #define GL_DEPTH_STENCIL GL_DEPTH_STENCIL_OES + #define GL_UNSIGNED_INT_24_8 GL_UNSIGNED_INT_24_8_OES + + #define glGenVertexArrays(...) + #define glDeleteVertexArrays(...) + #define glBindVertexArray(...) + + #define GL_PROGRAM_BINARY_LENGTH GL_PROGRAM_BINARY_LENGTH_OES + #define glGetProgramBinary(...) + #define glProgramBinary(...) #elif __linux__ #define LINUX 1 #include @@ -125,7 +157,8 @@ namespace Core { #include "input.h" #include "sound.h" -#if defined(WIN32) || defined(LINUX) || defined(ANDROID) + +#if defined(WIN32) || (defined(LINUX) && !defined(__RPI__)) || defined(ANDROID) #ifdef ANDROID #define GetProc(x) dlsym(libGL, x); @@ -133,6 +166,8 @@ namespace Core { void* GetProc(const char *name) { #ifdef WIN32 return (void*)wglGetProcAddress(name); + #elif __RPI__ + return (void*)eglGetProcAddress(name); #elif LINUX return (void*)glXGetProcAddress((GLubyte*)name); #endif @@ -417,7 +452,7 @@ namespace Core { void *libGL = dlopen("libGLESv2.so", RTLD_LAZY); #endif - #if defined(WIN32) || defined(LINUX) || defined(ANDROID) + #if defined(WIN32) || (defined(LINUX) && !defined(__RPI__)) || defined(ANDROID) #ifdef WIN32 GetProcOGL(glActiveTexture); #endif @@ -485,8 +520,9 @@ namespace Core { GetProcOGL(glProgramBinary); #endif + char *ext = (char*)glGetString(GL_EXTENSIONS); - //LOG("%s\n", ext); + LOG("%s\n", ext); support.shaderBinary = extSupport(ext, "_program_binary"); support.VAO = extSupport(ext, "_vertex_array_object"); @@ -505,7 +541,6 @@ namespace Core { support.profMarker = extSupport(ext, "_KHR_debug"); support.profTiming = extSupport(ext, "_timer_query"); #endif - char *vendor = (char*)glGetString(GL_VENDOR); LOG("Vendor : %s\n", vendor); LOG("Renderer : %s\n", glGetString(GL_RENDERER)); @@ -527,6 +562,7 @@ namespace Core { glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&defaultFBO); glGenFramebuffers(1, &FBO); + memset(rtCache, 0, sizeof(rtCache)); defaultTarget = NULL; @@ -541,7 +577,7 @@ namespace Core { uint32 data = 0x00000000; blackTex = new Texture(1, 1, Texture::RGBA, false, &data, false); data = 0xFFFFFFFF; - whiteTex = new Texture(1, 1, Texture::RGBA, false, &data, false); + whiteTex = new Texture(1, 1, Texture::RGBA, false, &data, false); } void free() { diff --git a/src/format.h b/src/format.h index 3bfd48c..03a1ddf 100644 --- a/src/format.h +++ b/src/format.h @@ -138,10 +138,10 @@ E( LEADBAR ) \ E( INV_LEADBAR ) \ E( MIDAS_TOUCH ) \ - E( KEY_1 ) \ - E( KEY_2 ) \ - E( KEY_3 ) \ - E( KEY_4 ) \ + E( KEY_ITEM_1 ) \ + E( KEY_ITEM_2 ) \ + E( KEY_ITEM_3 ) \ + E( KEY_ITEM_4 ) \ E( INV_KEY_1 ) \ E( INV_KEY_2 ) \ E( INV_KEY_3 ) \ @@ -638,7 +638,7 @@ namespace TR { bool isItem() { return (type >= PISTOLS && type <= AMMO_UZIS) || (type >= PUZZLE_1 && type <= PUZZLE_4) || - (type >= KEY_1 && type <= KEY_4) || + (type >= KEY_ITEM_1 && type <= KEY_ITEM_4) || (type == MEDIKIT_SMALL || type == MEDIKIT_BIG || type == SCION_1); // TODO: recheck all items } @@ -670,10 +670,10 @@ namespace TR { case PUZZLE_3 : return INV_PUZZLE_3; case PUZZLE_4 : return INV_PUZZLE_4; - case KEY_1 : return INV_KEY_1; - case KEY_2 : return INV_KEY_2; - case KEY_3 : return INV_KEY_3; - case KEY_4 : return INV_KEY_4; + case KEY_ITEM_1 : return INV_KEY_1; + case KEY_ITEM_2 : return INV_KEY_2; + case KEY_ITEM_3 : return INV_KEY_3; + case KEY_ITEM_4 : return INV_KEY_4; case LEADBAR : return INV_LEADBAR; //case TR::Entity::SCION : return TR::Entity::INV_SCION; @@ -683,14 +683,14 @@ namespace TR { static Type getKeyForHole(Type hole) { switch (hole) { - case PUZZLE_HOLE_1 : return PUZZLE_1; break; - case PUZZLE_HOLE_2 : return PUZZLE_2; break; - case PUZZLE_HOLE_3 : return PUZZLE_3; break; - case PUZZLE_HOLE_4 : return PUZZLE_4; break; - case KEY_HOLE_1 : return KEY_1; break; - case KEY_HOLE_2 : return KEY_2; break; - case KEY_HOLE_3 : return KEY_3; break; - case KEY_HOLE_4 : return KEY_4; break; + case PUZZLE_HOLE_1 : return PUZZLE_1; break; + case PUZZLE_HOLE_2 : return PUZZLE_2; break; + case PUZZLE_HOLE_3 : return PUZZLE_3; break; + case PUZZLE_HOLE_4 : return PUZZLE_4; break; + case KEY_HOLE_1 : return KEY_ITEM_1; break; + case KEY_HOLE_2 : return KEY_ITEM_2; break; + case KEY_HOLE_3 : return KEY_ITEM_3; break; + case KEY_HOLE_4 : return KEY_ITEM_4; break; default : return NONE; } } @@ -2030,4 +2030,4 @@ namespace TR { } } -#endif \ No newline at end of file +#endif diff --git a/src/game.h b/src/game.h index 0fd2ef9..7f7b455 100644 --- a/src/game.h +++ b/src/game.h @@ -19,9 +19,9 @@ namespace Game { void init(Stream *lvl, Stream *snd) { Core::init(); - Core::settings.detail.ambient = true; + Core::settings.detail.ambient = false; Core::settings.detail.lighting = true; - Core::settings.detail.shadows = true; + Core::settings.detail.shadows = false; Core::settings.detail.water = Core::support.texFloat || Core::support.texHalf; Core::settings.detail.contact = false; @@ -93,4 +93,4 @@ namespace Game { } } -#endif \ No newline at end of file +#endif diff --git a/src/platform/rpi/Makefile b/src/platform/rpi/Makefile new file mode 100644 index 0000000..86896ae --- /dev/null +++ b/src/platform/rpi/Makefile @@ -0,0 +1,28 @@ +OBJS=OpenLara.o +BIN=../../../bin/OpenLara.bin + +CFLAGS+=-D__RPI__ +LDFLAGS+=-L$(SDKSTAGE)/opt/vc/lib/ -lbrcmGLESv2 -lbrcmEGL -lbcm_host -lvcos -lvchiq_arm -lpthread -lrt -lm -L$(SDKSTAGE)/opt/vc/src/hello_pi/libs/vgfont + +INCLUDES+=-I$(SDKSTAGE)/opt/vc/include/ -I$(SDKSTAGE)/opt/vc/include/interface/vcos/pthreads -I$(SDKSTAGE)/opt/vc/include/interface/vmcs_host/linux -I./ + +all: $(BIN) $(LIB) + +%.o: %.c + @rm -f $@ + $(CC) $(CFLAGS) $(INCLUDES) -g -c $< -o $@ -Wno-deprecated-declarations + +%.o: %.cpp + @rm -f $@ + $(CXX) $(CFLAGS) $(INCLUDES) -g -c $< -o $@ -Wno-deprecated-declarations + +%.bin: $(OBJS) + $(CC) -o $@ -Wl,--whole-archive $(OBJS) $(LDFLAGS) -Wl,--no-whole-archive -rdynamic + +%.a: $(OBJS) + $(AR) r $@ $^ + +clean: + for i in $(OBJS); do (if test -e "$$i"; then ( rm $$i ); fi ); done + @rm -f $(BIN) $(LIB) + diff --git a/src/platform/rpi/build.sh b/src/platform/rpi/build.sh new file mode 100755 index 0000000..70a10f8 --- /dev/null +++ b/src/platform/rpi/build.sh @@ -0,0 +1,3 @@ +set -e +clang++ -std=c++11 -Os -s -g -fno-exceptions -fno-rtti -ffunction-sections -fdata-sections -Wl,--gc-sections -DNDEBUG -D__RPI__ main.cpp ../../libs/stb_vorbis/stb_vorbis.c -I/opt/vc/include -I../../ -o../../../bin/OpenLara.bin -L/opt/vc/lib/ -lbrcmGLESv2 -lbrcmEGL -lX11 -lm -lrt -lpthread -lpulse-simple -lpulse -lbcm_host -ludev +strip ../../../bin/OpenLara --strip-all --remove-section=.comment --remove-section=.note diff --git a/src/platform/rpi/main.cpp b/src/platform/rpi/main.cpp new file mode 100644 index 0000000..43e644d --- /dev/null +++ b/src/platform/rpi/main.cpp @@ -0,0 +1,466 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "game.h" + +#define WND_TITLE "OpenLara" + +#define SND_FRAME_SIZE 4 +#define SND_DATA_SIZE (1024 * SND_FRAME_SIZE) + +pa_simple *sndOut; +pthread_t sndThread; +pthread_mutex_t sndMutex; + +Sound::Frame *sndData; + +void* sndFill(void *arg) { + while (1) { + pthread_mutex_lock(&sndMutex); + Sound::fill(sndData, SND_DATA_SIZE / SND_FRAME_SIZE); + pthread_mutex_unlock(&sndMutex); + pa_simple_write(sndOut, sndData, SND_DATA_SIZE, NULL); + } + return NULL; +} + +void sndInit() { + static const pa_sample_spec spec = { + .format = PA_SAMPLE_S16LE, + .rate = 44100, + .channels = 2 + }; + + static const pa_buffer_attr attr = { + .maxlength = SND_DATA_SIZE * 2, + .tlength = 0xFFFFFFFF, + .prebuf = 0xFFFFFFFF, + .minreq = SND_DATA_SIZE, + .fragsize = 0xFFFFFFFF, + }; + + pthread_mutex_init(&sndMutex, NULL); + + int error; + if (!(sndOut = pa_simple_new(NULL, WND_TITLE, PA_STREAM_PLAYBACK, NULL, "game", &spec, NULL, &attr, &error))) { + LOG("! sound: pa_simple_new() %s\n", pa_strerror(error)); + sndData = NULL; + return; + } + + sndData = new Sound::Frame[SND_DATA_SIZE / SND_FRAME_SIZE]; + pthread_create(&sndThread, NULL, sndFill, NULL); +} + +void sndFree() { + if (sndOut) { + pthread_cancel(sndThread); + pthread_mutex_lock(&sndMutex); + // pa_simple_flush(sndOut, NULL); + // pa_simple_free(sndOut); + pthread_mutex_unlock(&sndMutex); + delete[] sndData; + } + pthread_mutex_destroy(&sndMutex); +} + +unsigned int startTime; + +int getTime() { + timeval t; + gettimeofday(&t, NULL); + return int((t.tv_sec - startTime) * 1000 + t.tv_usec / 1000); +} + +bool wndInit(DISPMANX_DISPLAY_HANDLE_T &display, EGL_DISPMANX_WINDOW_T &window) { + if (graphics_get_display_size(0, (uint32_t*)&window.width, (uint32_t*)&window.height) < 0) { + LOG("! can't get display size\n"); + return false; + } + + int scale = 1; + window.width /= scale; + window.height /= scale; + + VC_RECT_T dstRect, srcRect; + vc_dispmanx_rect_set(&dstRect, 0, 0, window.width, window.height); + vc_dispmanx_rect_set(&srcRect, 0, 0, window.width << 16, window.height << 16); + VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, 0xFF, 0 }; + + display = vc_dispmanx_display_open(0); + + DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0); + + window.element = vc_dispmanx_element_add( + update, display, 0, &dstRect, 0, &srcRect, + DISPMANX_PROTECTION_NONE, &alpha, NULL, DISPMANX_NO_ROTATE); + + vc_dispmanx_update_submit_sync(update); + + return true; +} + +void wndFree(DISPMANX_DISPLAY_HANDLE_T &display, EGL_DISPMANX_WINDOW_T &window) { + DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0); + vc_dispmanx_element_remove(update, window.element); + vc_dispmanx_update_submit_sync(update); + vc_dispmanx_display_close(display); +} + +bool eglInit(EGL_DISPMANX_WINDOW_T &window, EGLDisplay &display, EGLSurface &surface, EGLContext &context) { + static const EGLint eglAttr[] = { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 24, + EGL_SAMPLES, 0, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_NONE + }; + + static const EGLint ctxAttr[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (display == EGL_NO_DISPLAY) + return false; + + if (eglInitialize(display, NULL, NULL) == EGL_FALSE) + return false; + + EGLConfig config; + EGLint configCount; + + if (eglChooseConfig(display, eglAttr, &config, 1, &configCount) == EGL_FALSE) + return false; + + context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctxAttr); + if (context == EGL_NO_CONTEXT) + return false; + + surface = eglCreateWindowSurface(display, config, &window, NULL); + if (surface == EGL_NO_SURFACE) + return false; + + if (eglSurfaceAttrib(display, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED) == EGL_FALSE) + return false; + + if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) + return false; + + //eglSwapInterval(display, 0); // turn off vsync + + return true; +} + +void eglFree(EGLDisplay display, EGLSurface surface, EGLContext context) { + eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(display, surface); + eglDestroyContext(display, context); + eglTerminate(display); +} + +// Input +#define MAX_INPUT_DEVICES 16 +int inputDevices[MAX_INPUT_DEVICES]; + +udev *udevObj; +udev_monitor *udevMon; +int udevMon_fd; + +vec2 joyL, joyR; + +InputKey codeToInputKey(int code) { + switch (code) { + // keyboard + case KEY_LEFT : return ikLeft; + case KEY_RIGHT : return ikRight; + case KEY_UP : return ikUp; + case KEY_DOWN : return ikDown; + case KEY_SPACE : return ikSpace; + case KEY_TAB : return ikTab; + case KEY_ENTER : return ikEnter; + case KEY_ESC : return ikEscape; + case KEY_LEFTSHIFT : + case KEY_RIGHTSHIFT : return ikShift; + case KEY_LEFTCTRL : + case KEY_RIGHTCTRL : return ikCtrl; + case KEY_LEFTALT : + case KEY_RIGHTALT : return ikAlt; + case KEY_0 : return ik0; + case KEY_1 : return ik1; + case KEY_2 : return ik2; + case KEY_3 : return ik3; + case KEY_4 : return ik4; + case KEY_5 : return ik5; + case KEY_6 : return ik6; + case KEY_7 : return ik7; + case KEY_8 : return ik8; + case KEY_9 : return ik9; + case KEY_A : return ikA; + case KEY_B : return ikB; + case KEY_C : return ikC; + case KEY_D : return ikD; + case KEY_E : return ikE; + case KEY_F : return ikF; + case KEY_G : return ikG; + case KEY_H : return ikH; + case KEY_I : return ikI; + case KEY_J : return ikJ; + case KEY_K : return ikK; + case KEY_L : return ikL; + case KEY_M : return ikM; + case KEY_N : return ikN; + case KEY_O : return ikO; + case KEY_P : return ikP; + case KEY_Q : return ikQ; + case KEY_R : return ikR; + case KEY_S : return ikS; + case KEY_T : return ikT; + case KEY_U : return ikU; + case KEY_V : return ikV; + case KEY_W : return ikW; + case KEY_X : return ikX; + case KEY_Y : return ikY; + case KEY_Z : return ikZ; + // mouse + case BTN_LEFT : return ikMouseL; + case BTN_RIGHT : return ikMouseR; + case BTN_MIDDLE : return ikMouseM; + // gamepad + case KEY_HOMEPAGE : return ikEscape; + case BTN_A : return ikJoyA; + case BTN_B : return ikJoyB; + case BTN_X : return ikJoyX; + case BTN_Y : return ikJoyY; + case BTN_TL : return ikJoyLB; + case BTN_TR : return ikJoyRB; + case BTN_SELECT : return ikJoySelect; + case BTN_START : return ikJoyStart; + case BTN_THUMBL : return ikJoyL; + case BTN_THUMBR : return ikJoyR; + case BTN_TL2 : return ikJoyLT; + case BTN_TR2 : return ikJoyRT; + } + return ikNone; +} + +int inputDevIndex(const char *node) { + const char *str = strstr(node, "/event"); + if (str) + return atoi(str + 6); + return -1; +} + +void inputDevAdd(const char *node) { + int index = inputDevIndex(node); + if (index != -1) { + inputDevices[index] = open(node, O_RDONLY | O_NONBLOCK); + //ioctl(inputDevices[index], EVIOCGRAB, (void*)1); + LOG("input: add %s\n", node); + } +} + +void inputDevRemove(const char *node) { + int index = inputDevIndex(node); + if (index != -1 && inputDevices[index] != -1) { + close(inputDevices[index]); + LOG("input: remove %s\n", node); + } +} + +bool inputInit() { + joyL = joyR = vec2(0); + + for (int i = 0; i < MAX_INPUT_DEVICES; i++) + inputDevices[i] = -1; + + udevObj = udev_new(); + if (!udevObj) + return false; + + udevMon = udev_monitor_new_from_netlink(udevObj, "udev"); + udev_monitor_filter_add_match_subsystem_devtype(udevMon, "input", NULL); + udev_monitor_enable_receiving(udevMon); + udevMon_fd = udev_monitor_get_fd(udevMon); + + udev_enumerate *e = udev_enumerate_new(udevObj); + udev_enumerate_add_match_subsystem(e, "input"); + udev_enumerate_scan_devices(e); + udev_list_entry *devices = udev_enumerate_get_list_entry(e); + + udev_list_entry *entry; + udev_list_entry_foreach(entry, devices) { + const char *path, *node; + udev_device *device; + + path = udev_list_entry_get_name(entry); + device = udev_device_new_from_syspath(udevObj, path); + node = udev_device_get_devnode(device); + + if (node) + inputDevAdd(node); + } + udev_enumerate_unref(e); + + return true; +} + +void inputFree() { + for (int i = 0; i < MAX_INPUT_DEVICES; i++) + if (inputDevices[i] != -1) + close(inputDevices[i]); + udev_monitor_unref(udevMon); + udev_unref(udevObj); +} + +void inputUpdate() { +// get input events + input_event events[16]; + + for (int i = 0; i < MAX_INPUT_DEVICES; i++) { + if (inputDevices[i] == -1) continue; + int rb = read(inputDevices[i], events, sizeof(events)); + + input_event *e = events; + while (rb > 0) { + switch (e->type) { + case EV_KEY : { + InputKey key = codeToInputKey(e->code); + if (key == ikMouseL || key == ikMouseR || key == ikMouseM) + Input::setPos(key, Input::mouse.pos); + Input::setDown(key, e->value != 0); + break; + } + case EV_REL : { + vec2 delta(0); + delta[e->code] = float(e->value); + Input::setPos(ikMouseL, Input::mouse.pos + delta); + break; + } + case EV_ABS : { + float v = float(e->value) / 128.0f - 1.0f; + switch (e->code) { + case ABS_X : joyL.x = v; break; + case ABS_Y : joyL.y = v; break; + case ABS_Z : joyR.x = v; break; + case ABS_RZ : joyR.y = v; break; + } + } + } + //LOG("input: type = %d, code = %d, value = %d\n", int(e->type), int(e->code), int(e->value)); + e++; + rb -= sizeof(events[0]); + } + } + Input::setPos(ikJoyL, joyL); + Input::setPos(ikJoyR, joyR); +// monitoring plug and unplug input devices + fd_set fds; + FD_ZERO(&fds); + FD_SET(udevMon_fd, &fds); + + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + + if (select(udevMon_fd + 1, &fds, NULL, NULL, &tv) > 0 && FD_ISSET(udevMon_fd, &fds)) { + udev_device *device = udev_monitor_receive_device(udevMon); + if (device) { + const char *node = udev_device_get_devnode(device); + if (node) { + const char *action = udev_device_get_action(device); + if (!strcmp(action, "add")) + inputDevAdd(node); + if (!strcmp(action, "remove")) + inputDevRemove(node); + } + udev_device_unref(device); + } else + LOG("! input: receive_device\n"); + } +} + +char Stream::cacheDir[255]; +char Stream::contentDir[255]; + +int main() { + bcm_host_init(); + + DISPMANX_DISPLAY_HANDLE_T dmDisplay; + EGL_DISPMANX_WINDOW_T dmWindow; + if (!wndInit(dmDisplay, dmWindow)) + return 1; + Core::width = dmWindow.width; + Core::height = dmWindow.height; + + EGLDisplay display; + EGLSurface surface; + EGLContext context; + if (!eglInit(dmWindow, display, context, surface)) { + LOG("! can't initialize EGL context\n"); + return 1; + } + + inputInit(); + + Stream::contentDir[0] = Stream::cacheDir[0] = 0; + + const char *home; + if (!(home = getenv("HOME"))) + home = getpwuid(getuid())->pw_dir; + strcat(Stream::cacheDir, home); + strcat(Stream::cacheDir, "/.OpenLara/"); + + struct stat st = {0}; + if (stat(Stream::cacheDir, &st) == -1 && mkdir(Stream::cacheDir, 0777) == -1) + Stream::cacheDir[0] = 0; + + timeval t; + gettimeofday(&t, NULL); + startTime = t.tv_sec; + + sndInit(); + Game::init(); + + int lastTime = getTime(); + + while (!Input::down[ikEscape]) { + inputUpdate(); + + int time = getTime(); + if (time <= lastTime) + continue; + + pthread_mutex_lock(&sndMutex); + Game::update((time - lastTime) * 0.001f); + pthread_mutex_unlock(&sndMutex); + lastTime = time; + + Game::render(); + eglSwapBuffers(display, surface); + }; + + sndFree(); + Game::free(); + + inputFree(); + eglFree(display, surface, context); + wndFree(dmDisplay, dmWindow); + + return 0; +} diff --git a/src/utils.h b/src/utils.h index a8ce1cd..bf5da2c 100644 --- a/src/utils.h +++ b/src/utils.h @@ -21,11 +21,12 @@ #else #define ASSERT(expr) -// #ifdef PROFILE + #ifdef LINUX + #define LOG(...) printf(__VA_ARGS__); fflush(stdout) + #else #define LOG(...) printf(__VA_ARGS__) -// #else -// #define LOG(...) 0 -// #endif + // #define LOG(...) 0 + #endif #endif #ifdef ANDROID