diff --git a/project/jni/application/test-gles2/AndroidAppSettings.cfg b/project/jni/application/test-gles2/AndroidAppSettings.cfg new file mode 100644 index 000000000..3a639e529 --- /dev/null +++ b/project/jni/application/test-gles2/AndroidAppSettings.cfg @@ -0,0 +1,295 @@ +# The application settings for Android libSDL port + +# Specify application name (e.x. My Application) +AppName="GLES2 SDL test" + +# Specify reversed site name of application (e.x. com.mysite.myapp) +AppFullName=gles2.sdl.test + +# Application version code (integer) +AppVersionCode=1 + +# Application user-visible version name (string) +AppVersionName="1" + +# Specify path to download application data in zip archive in the form 'Description|URL|MirrorURL^Description2|URL2|MirrorURL2^...' +# If you'll start Description with '!' symbol it will be enabled by default, other downloads should be selected by user from startup config menu +# If the URL in in the form ':dir/file.dat:http://URL/' it will be downloaded as binary BLOB to the application dir and not unzipped +# If the URL does not contain 'http://' it is treated as file from 'project/jni/application/src/AndroidData' dir - +# these files are put inside .apk package by build system +# You can specify Google Play expansion files in the form 'obb:main.12345' or 'obb:patch.12345' where 12345 is the app version, first associated with the file +AppDataDownloadUrl="!!Data|data.zip" + +# Reset SDL config when updating application to the new version (y) / (n) +ResetSdlConfigForThisVersion=n + +# Delete application data files when upgrading (specify file/dir paths separated by spaces) +DeleteFilesOnUpgrade="%" + +# Here you may type readme text, which will be shown during startup. Format is: +# Text in English, use \\\\n to separate lines (that's four backslashes)^de:Text in Deutsch^ru:Text in Russian^button:Button that will open some URL:http://url-to-open/ +ReadmeText='^text' + +# libSDL version to use (1.2/1.3/2.0) +LibSdlVersion=1.2 + +# Specify screen orientation: (v)ertical/(p)ortrait or (h)orizontal/(l)andscape +ScreenOrientation=h + +# Video color depth - 16 BPP is the fastest and supported for all modes, 24 bpp is supported only +# with SwVideoMode=y, SDL_OPENGL mode supports everything. (16)/(24)/(32) +VideoDepthBpp=24 + +# Enable OpenGL depth buffer (needed only for 3-d applications, small speed decrease) (y) or (n) +NeedDepthBuffer=n + +# Enable OpenGL stencil buffer (needed only for 3-d applications, small speed decrease) (y) or (n) +NeedStencilBuffer=n + +# Use GLES 2.x context +# you need this option only if you're developing 3-d app (y) or (n) +NeedGles2=y + +# Use GLES 3.x context +# you need this option only if you're developing 3-d app (y) or (n) +NeedGles3=n + +# Use glshim library for provide OpenGL 1.x functionality to OpenGL ES accelerated cards (y) or (n) +UseGlshim=n + +# Application uses software video buffer - you're calling SDL_SetVideoMode() without SDL_HWSURFACE and without SDL_OPENGL, +# this will allow small speed optimization. Enable this even when you're using SDL_HWSURFACE. (y) or (n) +SwVideoMode=n + +# Application video output will be resized to fit into native device screen (y)/(n) +SdlVideoResize=n + +# Application resizing will keep 4:3 aspect ratio, with black bars at sides (y)/(n) +SdlVideoResizeKeepAspect=n + +# Do not allow device to sleep when the application is in foreground, set this for video players or apps which use accelerometer +InhibitSuspend=y + +# Create Android service, so the app is less likely to be killed while in background +CreateService=n + +# Application does not call SDL_Flip() or SDL_UpdateRects() appropriately, or draws from non-main thread - +# enabling the compatibility mode will force screen update every 100 milliseconds, which is laggy and inefficient (y) or (n) +CompatibilityHacksForceScreenUpdate=n + +# Application does not call SDL_Flip() or SDL_UpdateRects() after mouse click (ScummVM and all Amiga emulators do that) - +# force screen update by moving mouse cursor a little after each click (y) or (n) +CompatibilityHacksForceScreenUpdateMouseClick=n + +# Application initializes SDL audio/video inside static constructors (which is bad, you won't be able to run ndk-gdb) (y)/(n) +CompatibilityHacksStaticInit=n + +# On-screen Android soft text input emulates hardware keyboard, this will only work with Hackers Keyboard app (y)/(n) +CompatibilityHacksTextInputEmulatesHwKeyboard=n + +# Built-in text input keyboards with custom layouts for emulators, requires CompatibilityHacksTextInputEmulatesHwKeyboard=y +# 0 or empty - standard Android keyboard +# 1 - Simple QWERTY keyboard, no function keys, no arrow keys +# 2 - Commodore 64 keyboard +# 3 - Amiga keyboard +# 4 - Atari800 keyboard +TextInputKeyboard=0 + +# Hack for broken devices: prevent audio chopping, by sleeping a bit after pushing each audio chunk (y)/(n) +CompatibilityHacksPreventAudioChopping=n + +# Hack for broken apps: application ignores audio buffer size returned by SDL (y)/(n) +CompatibilityHacksAppIgnoresAudioBufferSize=n + +# Hack for VCMI: preload additional shared libraries before aplication start +CompatibilityHacksAdditionalPreloadedSharedLibraries="" + +# Hack for Free Heroes 2, which redraws the screen inside SDL_PumpEvents(): slow and compatible SDL event queue - +# do not use it with accelerometer/gyroscope, or your app may freeze at random (y)/(n) +CompatibilityHacksSlowCompatibleEventQueue=n + +# Save and restore OpenGL state when drawing on-screen keyboard for apps that use SDL_OPENGL +CompatibilityHacksTouchscreenKeyboardSaveRestoreOpenGLState=n + +# Application uses SDL_UpdateRects() properly, and does not draw in any region outside those rects. +# This improves drawing speed, but I know only one application that does that, and it's written by me (y)/(n) +CompatibilityHacksProperUsageOfSDL_UpdateRects= + +# Application uses mouse (y) or (n), this will show mouse emulation dialog to the user +AppUsesMouse=y + +# Application needs two-button mouse, will also enable advanced point-and-click features (y) or (n) +AppNeedsTwoButtonMouse=n + +# Right mouse button can do long-press/drag&drop action, necessary for some games (y) or (n) +# If you disable it, swiping with two fingers will send mouse wheel events +RightMouseButtonLongPress= + +# Show SDL mouse cursor, for applications that do not draw cursor at all (y) or (n) +ShowMouseCursor=n + +# Screen follows mouse cursor, when it's covered by soft keyboard, this works only in software video mode (y) or (n) +ScreenFollowsMouse= + +# Generate more touch events, by default SDL generates one event per one video frame, this is useful for drawing apps (y) or (n) +GenerateSubframeTouchEvents= + +# Force relative (laptop) mouse movement mode, useful when both on-screen keyboard and mouse are needed (y) or (n) +ForceRelativeMouseMode=n + +# Show on-screen dpad/joystick, that will act as arrow keys (y) or (n) +AppNeedsArrowKeys=n + +# On-screen dpad/joystick will appear under finger when it touches the screen (y) or (n) +# Joystick always follows finger, so moving mouse requires touching the screen with other finger +FloatingScreenJoystick= + +# Application needs text input (y) or (n), enables button for text input on screen +AppNeedsTextInput=y + +# Application uses joystick (y) or (n), the on-screen DPAD will be used as joystick 0 axes 0-1 +# This will disable AppNeedsArrowKeys option +AppUsesJoystick=n + +# Application uses second on-screen joystick, as SDL joystick 0 axes 2-3 (y)/(n) +AppUsesSecondJoystick=n + +# Application uses third on-screen joystick, as SDL joystick 0 axes 20-21 (y)/(n) +AppUsesThirdJoystick= + +# Application uses accelerometer (y) or (n), the accelerometer will be used as joystick 1 axes 0-1 and 5-7 +AppUsesAccelerometer=n + +# Application uses gyroscope (y) or (n), the gyroscope will be used as joystick 1 axes 2-4 +AppUsesGyroscope=n + +# Application uses orientation sensor (y) or (n), reported as joystick 1 axes 8-10 +AppUsesOrientationSensor= + +# Use gyroscope to move mouse cursor (y) or (n), it eats battery, and can be disabled in settings, do not use with AppUsesGyroscope setting +MoveMouseWithGyroscope= + +# Application uses multitouch (y) or (n), multitouch events are passed as SDL_JOYBALLMOTION events for the joystick 0 +AppUsesMultitouch=n + +# Application records audio (it will use any available source, such a s microphone) +# API is defined in file SDL_android.h: int SDL_ANDROID_OpenAudioRecording(SDL_AudioSpec *spec); void SDL_ANDROID_CloseAudioRecording(void); +# This option will add additional permission to Android manifest (y)/(n) +AppRecordsAudio=n + +# Application needs to access SD card. Always disable it, unless you want to access user photos and downloads. (y) / (n) +AccessSdCard= + +# Application needs Internet access. If you disable it, you'll have to bundle all your data files inside .apk (y) / (n) +AccessInternet= + +# Immersive mode - Android will hide on-screen Home/Back keys. Looks bad if you invoke Android keyboard. (y) / (n) +ImmersiveMode= + +# Application implements Android-specific routines to put to background, and will not draw anything to screen +# between SDL_ACTIVEEVENT lost / gained notifications - you should check for them +# rigth after SDL_Flip(), if (n) then SDL_Flip() will block till app in background (y) or (n) +# This option is reported to be buggy, sometimes failing to restore video state +NonBlockingSwapBuffers=n + +# Redefine common hardware keys to SDL keysyms +# BACK hardware key is available on all devices, MENU is available on pre-ICS devices, other keys may be absent +# SEARCH and CALL by default return same keycode as DPAD_CENTER - one of those keys is available on most devices +# Use word NO_REMAP if you want to preserve native functionality for certain key (volume keys are 3-rd and 4-th) +# Keys: TOUCHSCREEN (works only when AppUsesMouse=n), DPAD_CENTER/SEARCH, VOLUMEUP, VOLUMEDOWN, MENU, BACK, CAMERA +RedefinedKeys="RETURN" + +# Number of virtual keyboard keys (currently 6 is maximum) +AppTouchscreenKeyboardKeysAmount=0 + +# Redefine on-screen keyboard keys to SDL keysyms - 6 keyboard keys + 4 multitouch gestures (zoom in/out and rotate left/right) +RedefinedKeysScreenKb="RETURN" + +# Names for on-screen keyboard keys, such as Fire, Jump, Run etc, separated by spaces, they are used in SDL config menu +RedefinedKeysScreenKbNames="RETURN" + +# On-screen keys theme +# 0 = Ultimate Droid by Sean Stieber (green, with cross joystick) +# 1 = Simple Theme by Beholder (white, with cross joystick) +# 2 = Sun by Sirea (yellow, with round joystick) +# 3 = Keen by Gerstrong (multicolor, with round joystick) +# 4 = Retro by Santiago Radeff (red/white, with cross joystick) +# 5 = GameBoy from RetroArch +# 6 = PlayStation from RetroArch +# 7 = SuperNintendo from RetroArch +# 8 = DualShock from RetroArch +# 9 = Nintendo64 from RetroArch +TouchscreenKeysTheme=2 + +# Redefine gamepad keys to SDL keysyms, button order is: +# A B X Y L1 R1 L2 R2 LThumb RThumb +RedefinedKeysGamepad="RETURN" + +# How long to show startup menu button, in msec, 0 to disable startup menu +StartupMenuButtonTimeout=0 + +# Menu items to hide from startup menu, available menu items: +# SettingsMenu.OkButton SettingsMenu.DummyMenu SettingsMenu.MainMenu SettingsMenuMisc.DownloadConfig SettingsMenuMisc.OptionalDownloadConfig SettingsMenuMisc.AudioConfig SettingsMenuMisc.VideoSettingsConfig SettingsMenuMisc.ShowReadme SettingsMenuMisc.GyroscopeCalibration SettingsMenuMisc.CommandlineConfig SettingsMenuMisc.ResetToDefaultsConfig SettingsMenuMouse.MouseConfigMainMenu SettingsMenuMouse.DisplaySizeConfig SettingsMenuMouse.LeftClickConfig SettingsMenuMouse.RightClickConfig SettingsMenuMouse.AdditionalMouseConfig SettingsMenuMouse.JoystickMouseConfig SettingsMenuMouse.TouchPressureMeasurementTool SettingsMenuMouse.CalibrateTouchscreenMenu SettingsMenuKeyboard.KeyboardConfigMainMenu SettingsMenuKeyboard.ScreenKeyboardSizeConfig SettingsMenuKeyboard.ScreenKeyboardDrawSizeConfig SettingsMenuKeyboard.ScreenKeyboardThemeConfig SettingsMenuKeyboard.ScreenKeyboardTransparencyConfig SettingsMenuKeyboard.RemapHwKeysConfig SettingsMenuKeyboard.RemapScreenKbConfig SettingsMenuKeyboard.ScreenGesturesConfig SettingsMenuKeyboard.CustomizeScreenKbLayout SettingsMenuKeyboard.ScreenKeyboardAdvanced +HiddenMenuOptions='' + +# Menu items to show at startup - this is Java code snippet, leave empty for default +# new SettingsMenuMisc.ShowReadme(), (AppUsesMouse \&\& \! ForceRelativeMouseMode \? new SettingsMenuMouse.DisplaySizeConfig(true) : new SettingsMenu.DummyMenu()), new SettingsMenuMisc.OptionalDownloadConfig(true), new SettingsMenuMisc.GyroscopeCalibration() +# Available menu items: +# SettingsMenu.OkButton SettingsMenu.DummyMenu SettingsMenu.MainMenu SettingsMenuMisc.DownloadConfig SettingsMenuMisc.OptionalDownloadConfig SettingsMenuMisc.AudioConfig SettingsMenuMisc.VideoSettingsConfig SettingsMenuMisc.ShowReadme SettingsMenuMisc.GyroscopeCalibration SettingsMenuMisc.CommandlineConfig SettingsMenuMisc.ResetToDefaultsConfig SettingsMenuMouse.MouseConfigMainMenu SettingsMenuMouse.DisplaySizeConfig SettingsMenuMouse.LeftClickConfig SettingsMenuMouse.RightClickConfig SettingsMenuMouse.AdditionalMouseConfig SettingsMenuMouse.JoystickMouseConfig SettingsMenuMouse.TouchPressureMeasurementTool SettingsMenuMouse.CalibrateTouchscreenMenu SettingsMenuKeyboard.KeyboardConfigMainMenu SettingsMenuKeyboard.ScreenKeyboardSizeConfig SettingsMenuKeyboard.ScreenKeyboardDrawSizeConfig SettingsMenuKeyboard.ScreenKeyboardThemeConfig SettingsMenuKeyboard.ScreenKeyboardTransparencyConfig SettingsMenuKeyboard.RemapHwKeysConfig SettingsMenuKeyboard.RemapScreenKbConfig SettingsMenuKeyboard.ScreenGesturesConfig SettingsMenuKeyboard.CustomizeScreenKbLayout SettingsMenuKeyboard.ScreenKeyboardAdvanced +FirstStartMenuOptions='' + +# Minimum amount of RAM application requires, in Mb, SDL will print warning to user if it's lower +AppMinimumRAM=0 + +# GCC version, or 'clang' for CLANG +NDK_TOOLCHAIN_VERSION= + +# Specify architectures to compile, 'all' or 'y' to compile for all architectures. +# Available architectures: armeabi armeabi-v7a x86 mips arm64-v8a +MultiABI='armeabi-v7a' + +# Optional shared libraries to compile - removing some of them will save space +# MP3 support by libMAD is encumbered by patents and libMAD is GPL-ed +# Available libraries: mad (GPL-ed!) sdl_mixer sdl_image sdl_ttf sdl_net sdl_blitpool sdl_gfx sdl_sound intl xml2 lua jpeg png ogg flac tremor vorbis freetype xerces curl theora fluidsynth lzma lzo2 mikmod openal timidity zzip bzip2 yaml-cpp python boost_date_time boost_filesystem boost_iostreams boost_program_options boost_regex boost_signals boost_system boost_thread glu avcodec avdevice avfilter avformat avresample avutil swscale swresample bzip2 +CompiledLibraries="sdl_image" + +# Application uses custom build script AndroidBuild.sh instead of Android.mk (y) or (n) +CustomBuildScript=n + +# Aditional CFLAGS for application +AppCflags='-O2' + +# Aditional C++-specific compiler flags for application, added after AppCflags +AppCppflags='' + +# Additional LDFLAGS for application +AppLdflags='' + +# If application has headers with the same name as system headers, this option tries to fix compiler flags to make it compilable +AppOverlapsSystemHeaders= + +# Build only following subdirs (empty will build all dirs, ignored with custom script) +AppSubdirsBuild='' + +# Exclude these files from build +AppBuildExclude='' + +# Application command line parameters, including app name as 0-th param +AppCmdline='' + +# Screen size is used by Google Play to prevent an app to be installed on devices with smaller screens +# Minimum screen size that application supports: (s)mall / (m)edium / (l)arge +MinimumScreenSize=s + +# Your AdMob Publisher ID, (n) if you don't want advertisements +AdmobPublisherId=n + +# Your AdMob test device ID, to receive a test ad +AdmobTestDeviceId= + +# Your AdMob banner size (BANNER/FULL_BANNER/LEADERBOARD/MEDIUM_RECTANGLE/SMART_BANNER/WIDE_SKYSCRAPER/FULL_WIDTH:Height/Width:AUTO_HEIGHT/Width:Height) +AdmobBannerSize= + +# Google Play Game Services application ID, required for cloud saves to work +GooglePlayGameServicesId= + diff --git a/project/jni/application/test-gles2/AndroidData/data.zip b/project/jni/application/test-gles2/AndroidData/data.zip new file mode 100644 index 000000000..c197c2f0f Binary files /dev/null and b/project/jni/application/test-gles2/AndroidData/data.zip differ diff --git a/project/jni/application/test-gles2/Makefile b/project/jni/application/test-gles2/Makefile new file mode 100644 index 000000000..24974b1ea --- /dev/null +++ b/project/jni/application/test-gles2/Makefile @@ -0,0 +1,4 @@ + +sdl_hello: *.cpp + g++ -g3 -O0 -o $@ $? `sdl-config --cflags` `sdl-config --libs` -lGLESv2 -lSDL_image + unzip -o AndroidData/*.zip diff --git a/project/jni/application/test-gles2/icon.png b/project/jni/application/test-gles2/icon.png new file mode 100644 index 000000000..ad30aedf6 Binary files /dev/null and b/project/jni/application/test-gles2/icon.png differ diff --git a/project/jni/application/test-gles2/main.cpp b/project/jni/application/test-gles2/main.cpp new file mode 100644 index 000000000..8d9b36cae --- /dev/null +++ b/project/jni/application/test-gles2/main.cpp @@ -0,0 +1,418 @@ +#include +#include +#include + +#include + +#include +#include + +#ifdef __ANDROID__ +#include +#define printf(...) __android_log_print(ANDROID_LOG_INFO, "Test-GLES3", __VA_ARGS__) +#endif + +int screenWidth = 0; +int screenHeight = 0; + +GLuint drawTextureProgram = 0; +GLint drawTextureSamplerLocation = 0; + +static void initSDL() +{ + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK); + SDL_EnableUNICODE(1); + + screenWidth = SDL_GetVideoInfo()->current_w; + screenHeight = SDL_GetVideoInfo()->current_h; + + if ( ! SDL_SetVideoMode(screenWidth, screenHeight, 24, SDL_OPENGL|SDL_DOUBLEBUF|SDL_FULLSCREEN) ) + { + printf("Couldn't set GL video mode: %s\n", SDL_GetError()); + SDL_Quit(); + exit(2); + } +} + +static GLuint loadShader ( GLenum type, const char *shaderSrc ) +{ + GLuint shader; + GLint compiled; + + // Create the shader object + shader = glCreateShader ( type ); + + if ( shader == 0 ) + { + return 0; + } + + // Load the shader source + glShaderSource ( shader, 1, &shaderSrc, NULL ); + + // Compile the shader + glCompileShader ( shader ); + + // Check the compile status + glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled ); + + if ( !compiled ) + { + GLint infoLen = 0; + + glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen ); + + if ( infoLen > 1 ) + { + char *infoLog = (char *) malloc ( sizeof ( char ) * infoLen ); + + glGetShaderInfoLog ( shader, infoLen, NULL, infoLog ); + printf ( "===========> Error compiling shader:\n"); + printf ( "===========> %s\n", infoLog ); + printf ( "===========> %s\n", shaderSrc ); + + free ( infoLog ); + } + + glDeleteShader ( shader ); + return 0; + } + + return shader; + +} + +static GLuint loadProgram ( const char *vertShaderSrc, const char *fragShaderSrc ) +{ + GLuint vertexShader; + GLuint fragmentShader; + GLuint programObject; + GLint linked; + + // Load the vertex/fragment shaders + vertexShader = loadShader ( GL_VERTEX_SHADER, vertShaderSrc ); + + if ( vertexShader == 0 ) + { + return 0; + } + + fragmentShader = loadShader ( GL_FRAGMENT_SHADER, fragShaderSrc ); + + if ( fragmentShader == 0 ) + { + glDeleteShader ( vertexShader ); + return 0; + } + + // Create the program object + programObject = glCreateProgram ( ); + + if ( programObject == 0 ) + { + return 0; + } + + glAttachShader ( programObject, vertexShader ); + glAttachShader ( programObject, fragmentShader ); + + // Link the program + glLinkProgram ( programObject ); + + // Check the link status + glGetProgramiv ( programObject, GL_LINK_STATUS, &linked ); + + if ( !linked ) + { + GLint infoLen = 0; + + glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen ); + + if ( infoLen > 1 ) + { + char *infoLog = (char *) malloc ( sizeof ( char ) * infoLen ); + + glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog ); + printf ( "===========> Error linking program:\n" ); + printf ( "===========> %s\n", infoLog ); + + free ( infoLog ); + } + + glDeleteProgram ( programObject ); + return 0; + } + + // Free up no longer needed shader resources + glDeleteShader ( vertexShader ); + glDeleteShader ( fragmentShader ); + + return programObject; +} + +static void initShaders() +{ + char *vertexShaderStr = NULL; + asprintf( &vertexShaderStr, + "#version 100 \n" + "const highp float screenWidthDiv = 2.0 / %d.0; \n" + "const highp float screenHeightDiv = 2.0 / %d.0; \n" + "attribute highp vec2 a_position; \n" + "attribute highp vec2 a_texCoord; \n" + "attribute lowp vec4 a_color; \n" + "varying highp vec2 v_texCoord; \n" + "varying lowp vec4 v_color; \n" + "void main() \n" + "{ \n" + " gl_Position = vec4( \n" + " a_position.x * screenWidthDiv - 1.0, \n" + " 1.0 - a_position.y * screenHeightDiv, \n" + " 0, 1); \n" + " v_texCoord = a_texCoord; \n" + " v_color = a_color; \n" + "} \n" + , screenWidth, screenHeight ); + + const char *fragmentShaderStr = + "#version 100 \n" + "varying highp vec2 v_texCoord; \n" + "varying lowp vec4 v_color; \n" + "uniform sampler2D s_texture; \n" + "void main() \n" + "{ \n" + " gl_FragColor = texture2D( s_texture, v_texCoord ) * v_color; \n" + "} \n"; + + //printf("initShaders(): vertex shader:\n%s\n", vertexShaderStr); + //printf("initShaders(): fragment shader:\n%s\n", fragmentShaderStr); + + // Load the shaders and get a linked program object + drawTextureProgram = loadProgram ( vertexShaderStr, fragmentShaderStr ); + if (drawTextureProgram == 0) + { + printf("Could not init shaders\n"); + SDL_Quit(); + exit(2); + } + + free(vertexShaderStr); + + // Get the sampler location + drawTextureSamplerLocation = glGetUniformLocation ( drawTextureProgram, "s_texture" ); +} + +static void initGL() +{ + glViewport(0, 0, screenWidth, screenHeight); + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glActiveTexture ( GL_TEXTURE0 ); + + initShaders(); +} + +static void clearScreen() +{ + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); // Always clear your scene before rendering, unless you're sure that you'll fill whole screen with textures/models etc +} + +struct Sprite { + + + Sprite(const char * path, GLint wrap = GL_CLAMP_TO_EDGE) + { + w = h = texture = 0; + imagePath = path; + textureWrap = wrap; + loadTexture(); + } + + bool loadTexture() + { + SDL_Surface *pic; + + pic = IMG_Load(imagePath.c_str()); + + if (!pic) + { + printf("Error: image %s cannot be loaded\n", imagePath.c_str()); + return false; + } + if (pic->format->BitsPerPixel != 32 && pic->format->BitsPerPixel != 24) + { + printf("Error: image %s is %dbpp - it should be either 24bpp or 32bpp, images with palette are not supported\n", imagePath.c_str(), pic->format->BitsPerPixel); + SDL_FreeSurface(pic); + return false; + } + + GLenum glFormat = (pic->format->BitsPerPixel == 32 ? GL_RGBA : GL_RGB); + w = pic->w; + h = pic->h; + // GLES3 always supports non-power-of-two textures, no need to recalculate texture dimensions + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0, glFormat, w, h, 0, glFormat, GL_UNSIGNED_BYTE, pic->pixels); + SDL_FreeSurface(pic); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, textureWrap); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, textureWrap); + + return true; + } + + void draw(GLfloat x, GLfloat y, GLfloat width, GLfloat height, + GLfloat tex_x1 = 0.0f, GLfloat tex_y1 = 0.0f, GLfloat tex_x2 = 1.0f, GLfloat tex_y2 = 1.0f, + GLfloat r = 1.0f, GLfloat g = 1.0f, GLfloat b = 1.0f, GLfloat a = 1.0f) + { + if (texture == 0) + return; + + glUseProgram( drawTextureProgram ); + + GLfloat coords[] = { + x, y, // Position 0 + tex_x1, tex_y1, // TexCoord 0 + x, y + height, // Position 1 + tex_x1, tex_y2, // TexCoord 1 + x + width, y + height, // Position 2 + tex_x2, tex_y2, // TexCoord 2 + x + width, y, // Position 3 + tex_x2, tex_y1 // TexCoord 3 + }; + GLfloat color[] = { r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a }; + + // Load the vertex position + glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof ( GLfloat ), coords ); + // Load the texture coordinate + glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof ( GLfloat ), &coords[2] ); + glVertexAttribPointer( 2, 4, GL_FLOAT, GL_FALSE, 0, color ); + + glEnableVertexAttribArray( 0 ); + glEnableVertexAttribArray( 1 ); + glEnableVertexAttribArray( 2 ); + + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( GL_TEXTURE_2D, texture ); + + glUniform1i ( drawTextureSamplerLocation, 0 ); + + glDrawArrays ( GL_TRIANGLE_FAN, 0, 4 ); + } + + void draw(GLfloat x, GLfloat y) + { + draw(x, y, w, h); + } + + void drawColor(GLfloat x, GLfloat y, GLfloat width, GLfloat height, GLfloat r, GLfloat g, GLfloat b, GLfloat a) + { + draw(x, y, width, height, 0.0f, 0.0f, 1.0f, 1.0f, r, g, b, a); + } + + void drawColor(GLfloat x, GLfloat y, GLfloat r, GLfloat g, GLfloat b, GLfloat a) + { + drawColor(x, y, w, h, r, g, b, a); + } + + GLuint texture; + int w, h; + std::string imagePath; + GLint textureWrap; +}; + +int +main(int argc, char *argv[]) +{ + initSDL(); + initGL(); + + std::vector sprites; + sprites.push_back(Sprite("test.png")); + sprites.push_back(Sprite("element0.png")); + sprites.push_back(Sprite("element1.png")); + sprites.push_back(Sprite("element2.png")); + sprites.push_back(Sprite("element3.png")); + //sprites.push_back(Sprite("stars.jpg", GL_REPEAT)); // Repeating tiles + sprites.push_back(Sprite("stars.jpg", GL_MIRRORED_REPEAT)); // Looks nice + + float coords[][2] = { {0, 0}, + {200, 0}, + {300, 200}, + {400, 300} }; + + float pulse = 1.0f, pulseChange = 0.01f; + int anim = 1; + + while ( ! SDL_GetKeyState(NULL)[SDLK_ESCAPE] ) // Exit by pressing Back button + { + // clearScreen(); // Do not clear screen, we will fill the screens with tiled background image instead + sprites[5].draw(0, 0, screenWidth, screenHeight, + coords[0][0] / sprites[5].w * 3, + coords[0][0] / sprites[5].h * 2, + coords[0][0] / sprites[5].w * 3 + (float) screenWidth / sprites[5].w, + coords[0][0] / sprites[5].h * 2 + (float) screenHeight / sprites[5].h); + + sprites[1].drawColor(coords[0][0], coords[0][1], pulse, pulse, 1.0f - pulse, 1.0f); + sprites[2].draw(coords[1][0], coords[1][1], sprites[2].w * pulse * 4, sprites[2].h * pulse * 4); + sprites[3].draw(coords[2][0], coords[2][1], sprites[3].w * pulse * 4, sprites[3].h * 2); + sprites[4].draw(coords[3][0], coords[3][1], sprites[4].w, sprites[4].h * pulse * 2); + + sprites[1].draw(screenWidth / 2.0f - sprites[1].w / 2.0f, screenHeight / 2.0f - sprites[1].h / 2.0f); + sprites[1].draw(0 - sprites[1].w / 2.0f, 0 - sprites[1].h / 2.0f); + sprites[1].draw(screenWidth - sprites[1].w / 2.0f, screenHeight - sprites[1].h / 2.0f); + sprites[1].draw(0 - sprites[1].w / 2.0f, screenHeight - sprites[1].h / 2.0f); + sprites[1].draw(screenWidth - sprites[1].w / 2.0f, 0 - sprites[1].h / 2.0f); + + int mouseX = 0, mouseY = 0, buttons = 0; + buttons = SDL_GetMouseState(&mouseX, &mouseY); + sprites[0].drawColor(mouseX - sprites[0].w/2, mouseY - sprites[0].h/2, 1.0f, 1.0f, 1.0f, pulse); + + SDL_GL_SwapBuffers(); + SDL_Event event; + while( SDL_PollEvent(&event) ) + { + if(event.type == SDL_VIDEORESIZE) + { + // GL context was destroyed - reload all textures + initGL(); + for(int i = 0; i < sprites.size(); i++) + sprites[i].loadTexture(); + } + + if(event.type == SDL_KEYUP || event.type == SDL_KEYDOWN) + { + printf("SDL key event: evt %s state %s key %4d %12s scancode %4d mod %2d unicode %d", event.type == SDL_KEYUP ? "UP " : "DOWN" , event.key.state == SDL_PRESSED ? "PRESSED " : "RELEASED", (int)event.key.keysym.sym, SDL_GetKeyName(event.key.keysym.sym), (int)event.key.keysym.scancode, (int)event.key.keysym.mod, (int)event.key.keysym.unicode); + if(event.key.keysym.sym == SDLK_ESCAPE) + return 0; + } + } + + // Some kinda animation + + pulse += pulseChange; + if(pulse >= 1.0f) + pulseChange = -0.01f; + if(pulse <= 0) + pulseChange = 0.01f; + + for(int i = 0; i < 4; i++) + { + coords[i][0] += anim; + coords[i][1] += anim; + } + if( coords[0][0] < 0 ) + anim = 1; + if( coords[3][1] > screenHeight ) + anim = -1; + } + + SDL_Quit(); + return 0; +}