├── .gitignore ├── .gitmodules ├── CSDL.h ├── LICENSE_v.txt ├── Makefile ├── README.md ├── Shader.h ├── cratesan ├── README.md ├── Rust │ ├── .gitignore │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ ├── rustfmt.toml │ └── src │ │ └── main.rs ├── V │ ├── README.md │ └── cratesan.v └── res │ ├── images │ ├── crate.png │ ├── cratesan.png │ ├── empty.png │ ├── player.png │ ├── splayer.png │ ├── store.png │ ├── stored.png │ └── wall.png │ └── levels │ └── levels.txt ├── fonts └── RobotoMono-Regular.ttf ├── game ├── C │ ├── Makefile │ └── game.c └── Rust │ ├── Cargo.toml │ └── src │ └── main.rs ├── glfnt.cpp ├── images ├── gb_head.png └── v-logo_30_30.png ├── main_c.c ├── main_cpp.cpp ├── maingl_c.c ├── maingl_v.v ├── mainglsl_c.c ├── mainmix_c.c ├── sdl.mak ├── sdl1 ├── Makefile ├── SDL.h └── main12.c ├── shaders ├── text.frag └── text.vs ├── sounds ├── LICENSE ├── SuperTwintrisThoseThree.mod ├── TwintrisAudiokraft.mod ├── TwintrisThosenine.mod ├── TwintrisWerethedevils.mod ├── block.wav ├── door1.wav ├── door2.wav ├── double.wav ├── line.wav ├── single.wav └── triple.wav ├── tetris_v.png ├── tetris_v.v ├── tetrisnomix_v.v ├── tex2glad.cpp ├── tex3glad.cpp ├── tex4glad.cpp ├── texglad.cpp ├── textures └── wall.jpg ├── tvintris.png ├── tvintris0_v.v ├── tvintrisgl.gif ├── tvintrisgl.png ├── tvintrisgl_v.v ├── vig.png ├── vnk.png ├── vsdl ├── vsdl.v └── vsdlstub.c └── vsdl2gl ├── LICENSE ├── README.md ├── examples └── tvintris │ ├── README.md │ ├── fonts │ └── RobotoMono-Regular.ttf │ ├── sounds │ ├── TwintrisThosenine.mod │ ├── block.wav │ ├── single.wav │ └── triple.wav │ ├── tvintris.png │ └── tvintris.v ├── v.mod └── vsdl2gl.v /.gitignore: -------------------------------------------------------------------------------- 1 | v 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vsdl2"] 2 | path = nsauzede/vsdl2 3 | url = https://github.com/nsauzede/vsdl2.git 4 | [submodule "nsauzede/vig"] 5 | path = nsauzede/vig 6 | url = https://github.com/nsauzede/vig 7 | [submodule "nsauzede/vnk"] 8 | path = nsauzede/vnk 9 | url = https://github.com/nsauzede/vnk 10 | -------------------------------------------------------------------------------- /CSDL.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | class CSDL { 6 | public: 7 | CSDL() : 8 | m_w(0), 9 | m_h(0), 10 | m_bpp(0), 11 | m_screen(0){ 12 | } 13 | void Init( int _w = 100, int _h = 100, int _bpp = 32) { 14 | #ifdef SDL1 15 | #define SDLV 1 16 | #else 17 | #define SDLV 2 18 | #endif 19 | SDL_Init( SDL_INIT_VIDEO); 20 | 21 | m_w = _w; 22 | m_h = _h; 23 | m_bpp = _bpp; 24 | m_screen = 0; 25 | #ifdef SDL2 26 | m_sdlWindow = 0; 27 | m_sdlRenderer = 0; 28 | m_sdlTexture = 0; 29 | #endif 30 | 31 | #ifdef SDL1 32 | m_screen = SDL_SetVideoMode( m_w, m_h, m_bpp, 0 33 | // || SDL_FULLSCREEN 34 | ); 35 | SDL_EnableKeyRepeat( 1+0*SDL_DEFAULT_REPEAT_DELAY, 1+0*SDL_DEFAULT_REPEAT_INTERVAL); 36 | #else 37 | SDL_CreateWindowAndRenderer( m_w, m_h, 0 38 | // || SDL_WINDOW_FULLSCREEN_DESKTOP 39 | , &m_sdlWindow, &m_sdlRenderer); 40 | m_screen = SDL_CreateRGBSurface( 0, m_w, m_h, m_bpp, 41 | 0x00FF0000, 42 | 0x0000FF00, 43 | 0x000000FF, 44 | 0xFF000000); 45 | m_sdlTexture = SDL_CreateTexture( m_sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, m_w, m_h); 46 | #endif 47 | if (!m_screen) { 48 | printf( "failed to init SDL\n"); 49 | exit( 1); 50 | } 51 | atexit( SDL_Quit); 52 | } 53 | enum { NONE, QUIT, LEFT, RIGHT, UP, DOWN, PUP, PDOWN, K_d, K_j}; 54 | int Poll( int *_ctrl = 0, int *_shift = 0) { 55 | int result = NONE; 56 | SDL_Event event; 57 | int ctrl = 0; 58 | int shift = 0; 59 | while (SDL_PollEvent( &event)) { 60 | if (event.type == SDL_QUIT) { 61 | result = QUIT; 62 | break; 63 | } 64 | #ifdef SDL1 65 | #if 0 66 | else if (event.type == SDL_MOUSEBUTTONDOWN) { 67 | if (event.button == SDL_BUTTON_WHEELUP) 68 | result = PUP; 69 | else if (event.button == SDL_BUTTON_WHEELUP) 70 | result = PDOWN; 71 | } 72 | #endif 73 | #else 74 | else if (event.type == SDL_MOUSEWHEEL) { 75 | int deltax = 0; 76 | int deltay = 0; 77 | static int last_x = -1; 78 | int x = event.wheel.x; 79 | static int last_y = -1; 80 | int y = event.wheel.y; 81 | if (last_x != -1) { 82 | deltax = x - last_x; 83 | } 84 | if (last_y != -1) { 85 | deltay = y - last_y; 86 | } 87 | last_x = x; 88 | last_y = y; 89 | if (deltax < 0) 90 | result = LEFT; 91 | else if (deltax > 0) 92 | result = RIGHT; 93 | else if (deltay < 0) 94 | result = UP; 95 | else if (deltay > 0) 96 | result = DOWN; 97 | } 98 | #endif 99 | else if (event.type == SDL_MOUSEMOTION) { 100 | int deltax = 0; 101 | int deltay = 0; 102 | static int last_x = -1; 103 | int x = event.motion.x; 104 | static int last_y = -1; 105 | int y = event.motion.y; 106 | if (last_x != -1) { 107 | deltax = x - last_x; 108 | } 109 | if (last_y != -1) { 110 | deltay = y - last_y; 111 | } 112 | last_x = x; 113 | last_y = y; 114 | if (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(SDL_BUTTON_LEFT)) { 115 | if (deltax < 0) 116 | result = LEFT; 117 | else if (deltax > 0) 118 | result = RIGHT; 119 | else if (deltay < 0) 120 | result = UP; 121 | else if (deltay > 0) 122 | result = DOWN; 123 | } 124 | } 125 | else if (event.type == SDL_KEYDOWN) { 126 | if (event.key.keysym.mod & KMOD_CTRL) 127 | ctrl = 1; 128 | if (event.key.keysym.mod & KMOD_SHIFT) 129 | shift = 1; 130 | if (event.key.keysym.sym == SDLK_ESCAPE) { 131 | result = QUIT; 132 | break; 133 | } 134 | else if (event.key.keysym.sym == SDLK_LEFT) { 135 | result = LEFT; 136 | break; 137 | } 138 | else if (event.key.keysym.sym == SDLK_RIGHT) { 139 | result = RIGHT; 140 | break; 141 | } 142 | else if (event.key.keysym.sym == SDLK_UP) { 143 | result = UP; 144 | break; 145 | } 146 | else if (event.key.keysym.sym == SDLK_DOWN) { 147 | result = DOWN; 148 | break; 149 | } 150 | else if (event.key.keysym.sym == SDLK_PAGEUP) { 151 | result = PUP; 152 | break; 153 | } 154 | else if (event.key.keysym.sym == SDLK_PAGEDOWN) { 155 | result = PDOWN; 156 | break; 157 | } 158 | else if (event.key.keysym.sym == SDLK_d) { 159 | result = K_d; 160 | break; 161 | } 162 | else if (event.key.keysym.sym == SDLK_j) { 163 | result = K_j; 164 | break; 165 | } 166 | } 167 | } 168 | if (_ctrl) 169 | *_ctrl = ctrl; 170 | if (_shift) 171 | *_shift = shift; 172 | if (result != NONE) { 173 | // printf( "ctrl=%d shift=%d\n", ctrl, shift); 174 | } 175 | return result; 176 | } 177 | void Draw( double *arr = 0) { 178 | SDL_Rect rect; 179 | if (arr) { 180 | rect.w = 1; 181 | rect.h = 1; 182 | double *_arr = arr; 183 | for (unsigned jj = 0; jj < m_h; jj++) { 184 | rect.y = jj; 185 | for (unsigned ii = 0; ii < m_w; ii++) { 186 | rect.x = ii; 187 | unsigned r, g, b; 188 | r = _arr[0] * 255; 189 | g = _arr[1] * 255; 190 | b = _arr[2] * 255; 191 | Uint32 col = SDL_MapRGB( m_screen->format, r, g, b); 192 | SDL_FillRect( m_screen, &rect, col); 193 | _arr += 3; 194 | } 195 | } 196 | } 197 | else { 198 | rect.x = 0; 199 | rect.y = 0; 200 | rect.w = m_w; 201 | rect.h = m_h; 202 | Uint32 col = SDL_MapRGB( m_screen->format, 128, 0, 0); 203 | SDL_FillRect( m_screen, &rect, col); 204 | } 205 | #ifdef SDL1 206 | SDL_UpdateRect( m_screen, 0, 0, 0, 0); 207 | #else 208 | SDL_UpdateTexture( m_sdlTexture, NULL, m_screen->pixels, m_screen->pitch); 209 | SDL_RenderClear( m_sdlRenderer); 210 | SDL_RenderCopy( m_sdlRenderer, m_sdlTexture, NULL, NULL); 211 | SDL_RenderPresent( m_sdlRenderer); 212 | #endif 213 | } 214 | void Delay( unsigned millis) { 215 | SDL_Delay( millis); 216 | } 217 | private: 218 | unsigned int m_w; 219 | unsigned int m_h; 220 | unsigned int m_bpp; 221 | SDL_Surface *m_screen; 222 | #ifdef SDL2 223 | SDL_Window *m_sdlWindow; 224 | SDL_Renderer *m_sdlRenderer; 225 | SDL_Texture *m_sdlTexture; 226 | #endif 227 | }; 228 | -------------------------------------------------------------------------------- /LICENSE_v.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Nicolas Sauzede 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | _SYS:=$(shell uname -o) 2 | ifeq ($(_SYS),Msys) 3 | WIN32:=1 4 | endif 5 | 6 | TARGET:= 7 | TARGET+=main_cpp.exe 8 | TARGET+=main_c.exe 9 | TARGET+=mainmix_c.exe 10 | TARGET+=maingl_c.exe 11 | #TARGET+=main_v.exe 12 | TARGET+=nsauzede/vsdl2/examples/main_v.exe 13 | #TARGET+=tetris_v.exe 14 | #TARGET+=tetrisnomix_v.exe 15 | #TARGET+=tvintris.exe 16 | #TARGET+=tvintris0_v.exe 17 | #TARGET+=tvintrisgl_v.exe 18 | #TARGET+=maingl_v.exe 19 | TARGET+=glfnt.exe 20 | ifndef WIN32 21 | TARGET+=mainnk_v.exe 22 | TARGET+=mainig_v.exe 23 | endif 24 | 25 | #CFLAGS:= 26 | CFLAGS+=-Wall 27 | #CFLAGS+=-Werror 28 | CFLAGS+=-Wextra 29 | #CFLAGS+=-pedantic 30 | CFLAGS+=-Wno-unused-variable 31 | CFLAGS+=-Wno-unused-parameter 32 | CFLAGS+=-Wno-unused-result 33 | 34 | CXXFLAGS:= 35 | CXXFLAGS+=-Wall 36 | CXXFLAGS+=-Werror 37 | CXXFLAGS+=-Wextra 38 | 39 | CXXFLAGS+=-g 40 | CFLAGS+=-g 41 | 42 | ifdef NOPT 43 | CXXFLAGS+=-O0 44 | CFLAGS+=-O0 45 | endif 46 | 47 | CXXFLAGS+=-I. 48 | 49 | V:=./v/v 50 | #VFLAGS:=-debug -show_c_cmd 51 | VCFLAGS:=-std=gnu11 -w -g -O0 52 | 53 | ifdef WIN32 54 | GLLDLIBS:=-lopengl32 -lglu32 55 | else 56 | GLLDLIBS:=-lGL -lGLU 57 | endif 58 | 59 | GLADFLAGS:=-I ../v/thirdparty/ -I ../stb 60 | GLADLIBS:=../v/thirdparty/glad/glad.o -l dl -lglfw 61 | 62 | LDLIBS+=-L. -lgc 63 | AR:=ar 64 | 65 | all: SDL_CHECK SUBM_CHECK VMOD_CHECK $(TARGET) 66 | 67 | VMOD_CHECK: V_CHECK NSAUZEDE_CHECK VSDL2_CHECK VNK_CHECK VIG_CHECK 68 | 69 | nsauzede/vig/README.md: 70 | git submodule deinit --force --all 71 | git submodule update --init --recursive 72 | 73 | SUBM_CHECK: nsauzede/vig/README.md 74 | 75 | GC_CHECK: libgc.a 76 | 77 | ifdef WIN32 78 | GLLIBS:=-lGLEW32 -lopengl32 -lfreetype -lglfw3 -pthread 79 | else 80 | GLLIBS:=-lGLEW -lGL -lfreetype -lglfw -ldl -lX11 -pthread 81 | endif 82 | glfnt.exe: glfnt.cpp 83 | g++ $^ $(CXXFLAGS) -o $@ `pkg-config freetype2 --cflags` -I v/thirdparty/ $(GLLIBS) 84 | 85 | %gl_c.exe: LDLIBS+=$(GLLDLIBS) 86 | %glsl_c.exe: LDLIBS+=$(GLLDLIBS) 87 | %gl_v.exe: LDLIBS+=$(GLLDLIBS) 88 | %glad.exe: CXXFLAGS+=$(GLADFLAGS) 89 | %glad.exe: LDLIBS+=$(GLADLIBS) 90 | 91 | libgc.o: v/thirdparty/libgc/gc.c 92 | $(CC) -c $< -o $@ 93 | libgc.a: libgc.o 94 | $(AR) cr $@ $^ 95 | 96 | include sdl.mak 97 | ifeq ($(SDL_VER),1) 98 | SDL_FLAGS+=-DSDL1 99 | else 100 | SDL_FLAGS+=-DSDL2 101 | endif 102 | 103 | #CFLAGS+=$(SDL_FLAGS) 104 | #CXXFLAGS+=$(SDL_FLAGS) 105 | %_cpp.exe: CXXFLAGS+=$(SDL_FLAGS) 106 | %_c.exe: CFLAGS+=$(SDL_FLAGS) 107 | %_v.exe: CFLAGS+=$(SDL_FLAGS) 108 | tvintris.exe: CFLAGS+=$(SDL_FLAGS) 109 | 110 | ifeq ($(SDL_VER),1) 111 | LDLIBS+=$(SDL_LIBS) -lSDL_ttf -lSDL_mixer 112 | else 113 | LDLIBS+=$(SDL_LIBS) -lSDL2_ttf -lSDL2_mixer -lSDL2_image 114 | endif 115 | 116 | CFLAGS+=-pthread 117 | CXXFLAGS+=-pthread 118 | LDFLAGS+=-pthread 119 | 120 | V_CHECK: $(V) GC_CHECK 121 | 122 | $(V): 123 | git clone --filter=tree:0 https://github.com/nsauzede/v 124 | (cd $(@D) ; $(MAKE) ; cd -) 125 | 126 | %ig_v.exe: CFLAGS+=-Insauzede/vig -DCIMGUI_DEFINE_ENUMS_AND_STRUCTS=1 -DIMGUI_DISABLE_OBSOLETE_FUNCTIONS=1 -DIMGUI_IMPL_API= $(SDL_FLAGS) 127 | %ig_v.exe: LDFLAGS= 128 | %ig_v.exe: LDLIBS+=nsauzede/vig/imgui_impl_sdl2.o nsauzede/vig/imgui_impl_opengl3.o nsauzede/vig/cimgui/bld/CMakeFiles/cimgui.dir/cimgui.cpp.o nsauzede/vig/cimgui/bld/CMakeFiles/cimgui.dir/imgui/*.cpp.o $(SDL_LIBS) -lGL -lGLEW -lm -ldl 129 | 130 | mainig.tmp.c: nsauzede/vig/examples/mainig/mainig.v | VIG_CHECK 131 | $(V) -o $@ $(VFLAGS) $^ 132 | mainig_v.exe: mainig.tmp.o 133 | $(CXX) -o $@ $(LDFLAGS) $^ $(LDLIBS) 134 | 135 | NSAUZEDE_CHECK: 136 | mkdir -p $(HOME)/.vmodules 137 | rm -Rf $(HOME)/.vmodules/nsauzede 138 | ln -sf $(PWD)/nsauzede $(HOME)/.vmodules 139 | 140 | $(HOME)/.vmodules/nsauzede/vig/v.mod: 141 | $(V) install nsauzede.vig 142 | 143 | #.PHONY: _VIG_CHECK VIG_CHECK 144 | _VIG_CHECK: 145 | touch nsauzede/vig/v.mod 146 | 147 | VIG_CHECK: _VIG_CHECK $(HOME)/.vmodules/nsauzede/vig/v.mod 148 | $(MAKE) -C nsauzede/vig 149 | 150 | %ig_v.exe: %ig_v.o | VIG_CHECK 151 | $(CC) -o $@ $(LDFLAGS) $^ $(LDLIBS) 152 | 153 | ifdef WIN32 154 | NKLDLIBS:=-lopengl32 -lglew32 155 | else 156 | NKLDLIBS:=-lGL -lGLEW 157 | endif 158 | 159 | %nk_v.exe: CFLAGS+=-Insauzede/vnk -DNK_INCLUDE_FIXED_TYPES -DNK_INCLUDE_STANDARD_IO -DNK_INCLUDE_STANDARD_VARARGS -DNK_INCLUDE_DEFAULT_ALLOCATOR -DNK_INCLUDE_VERTEX_BUFFER_OUTPUT -DNK_INCLUDE_FONT_BAKING -DNK_INCLUDE_DEFAULT_FONT -DNK_IMPLEMENTATION -DNK_SDL_GL3_IMPLEMENTATION $(SDL_FLAGS) 160 | %nk_v.exe: LDFLAGS= 161 | %nk_v.exe: LDLIBS+=$(SDL_LIBS) $(NKLDLIBS) -lm 162 | 163 | $(HOME)/.vmodules/nsauzede/vsdl2/v.mod: 164 | $(V) install nsauzede.vsdl2 165 | 166 | #.PHONY: _VSDL2_CHECK VSDL2_CHECK 167 | _VSDL2_CHECK: 168 | touch nsauzede/vsdl2/v.mod 169 | 170 | VSDL2_CHECK: _VSDL2_CHECK $(HOME)/.vmodules/nsauzede/vsdl2/v.mod 171 | 172 | $(HOME)/.vmodules/nsauzede/vnk/v.mod: 173 | $(V) install nsauzede.vnk 174 | 175 | #.PHONY: _VNK_CHECK VNK_CHECK 176 | _VNK_CHECK: 177 | touch nsauzede/vnk/v.mod 178 | 179 | VNK_CHECK: _VNK_CHECK $(HOME)/.vmodules/nsauzede/vnk/v.mod 180 | $(MAKE) -C nsauzede/vnk 181 | 182 | mainnk_v.c: nsauzede/vnk/examples/mainnk_v/mainnk_v.v 183 | $(V) -o $@ $(VFLAGS) $^ 184 | 185 | %nk_v.exe: %nk_v.o | VNK_CHECK 186 | $(CC) -o $@ $(LDFLAGS) $^ $(LDLIBS) 187 | 188 | %.exe: %.o 189 | $(CXX) -o $@ $(LDFLAGS) $^ $(LDLIBS) 190 | 191 | vsdlstub.o: vsdl/vsdlstub.c 192 | $(CC) -c -o $@ $(CFLAGS) -g $^ 193 | 194 | ifdef WIN32 195 | CFLAGS+=-Wno-incompatible-pointer-types 196 | endif 197 | 198 | tvintris.tmp.c: nsauzede/vsdl2/examples/tvintris/tvintris.v 199 | $(V) -o $@ $(VFLAGS) $^ 200 | tvintris.exe: tvintris.tmp.o 201 | $(CXX) -o $@ $(LDFLAGS) $^ $(LDLIBS) 202 | 203 | %_v.exe: CFLAGS+=$(VCFLAGS) 204 | #%_v.exe: LDLIBS+=vsdlstub.o 205 | #%.c: %.v | vsdlstub.o 206 | %.c: %.v 207 | # $(MAKE) -s $(V) 208 | $(V) -o $@ $(VFLAGS) $^ 209 | 210 | clean: 211 | $(RM) $(TARGET) *.o *_v.c 212 | 213 | clobber: clean 214 | $(RM) *~ *.exe fns.txt *.tmp.c .tmp.*.c *.so *_v 215 | 216 | mrproper: clobber 217 | $(RM) -Rf v 218 | $(MAKE) -C nsauzede/vig clobber 219 | $(MAKE) -C nsauzede/vnk clobber 220 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sdl2test 2 | Small examples of libSDL2 usage in V, C and C++ languages. 3 | Historically, the purpose was to evaluate the changes from SDL1 to SDL2. 4 | 5 | Note that the V modules wrapping : SDL2, Imgui and Nuklear have been moved to their separate git repo, and are still used/demonstrated here as git sub-modules. 6 | 7 | You can find their own repos here: 8 | - [vsdl2 SDL2 V wrapper](https://github.com/nsauzede/vsdl2) 9 | - [vig ImGui V wrapper](https://github.com/nsauzede/vig) 10 | - [vnk Nuklear V wrapper](https://github.com/nsauzede/vnk) 11 | 12 | ---- 13 | - cratesan is a Sokoban clone, in Rust and V 14 | 15 | 16 | 17 | - tvintris_v.v is a dual-player (local) version, inspired by ancient game Twintris. It uses published vpm module nsauzede.vsdl2 18 | 19 | 20 | 21 | - tvintrisgl_v.v is a dual-player (local) version with OpenGL, inspired by ancient game Twintris. It uses published vpm module nsauzede.vsdl2 22 | This OpenGL version still lacks TTF font for now, however 23 | 24 | 25 | 26 | 27 | 28 | # Credits 29 | - tetris_v.v is just and SDL2 port of original source from vlang/v example by Alex 30 | I wrote a simple SDL2 V wrapper, ported GLFW usage to SDL2, tweaked colors and added music & sounds 31 | 32 | 33 | 34 | Colors, Music and Sounds ripped from amiga title Twintris (1990 nostalgia !) 35 | - Graphician : Svein Berge 36 | - Musician : Tor Bernhard Gausen (Walkman/Cryptoburners) 37 | 38 | # Dependencies 39 | Ubuntu : 40 | `$ sudo apt install libsdl2-ttf-dev libsdl2-mixer-dev libssl-dev` 41 | And optionally for extra tests : 42 | `$ sudo apt install libglfw3-dev libglm-dev libfreetype-dev` 43 | 44 | Archlinux: 45 | `$ sudo pacman -S glew glm` 46 | And maybe other similar packages as for Ubuntu above? 47 | 48 | ClearLinux : (maybe miss libopenssl dev ?) 49 | `$ sudo swupd bundle-add devpkg-SDL2_ttf devpkg-SDL2_mixer` 50 | 51 | Windows/MSYS2 : (maybe miss libopenssl dev ?) 52 | `$ pacman -S mingw-w64-x86_64-SDL2_ttf mingw-w64-x86_64-SDL2_mixer` 53 | 54 | # How to build all (including vsdl2, vnk, vig..) 55 | Eg: on Linux: 56 | ``` 57 | sdl2test$ make 58 | ``` 59 | Can then run eg: VNK, VIG demo: 60 | ``` 61 | sdl2test$ ./mainnk.exe 62 | sdl2test$ ./mainig.exe 63 | ``` 64 | 65 | # Misc 66 | Makefile auto-detects available SDL version (2 or 1) 67 | 68 | Old notes: 69 | - vsdl : naive V wrapper for SDL2 binding (obsolete - rather see nsauzede/vsdl2) 70 | - CSDL : small C++ class to abstract SDL1/2 71 | - various C and V examples 72 | -------------------------------------------------------------------------------- /Shader.h: -------------------------------------------------------------------------------- 1 | #ifndef SHADER_H 2 | #define SHADER_H 3 | 4 | //#include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define nullptr 0 13 | 14 | class Shader 15 | { 16 | public: 17 | unsigned int ID; 18 | // constructor generates the shader on the fly 19 | // ------------------------------------------------------------------------ 20 | Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr) 21 | { 22 | // 1. retrieve the vertex/fragment source code from filePath 23 | std::string vertexCode; 24 | std::string fragmentCode; 25 | std::string geometryCode; 26 | std::ifstream vShaderFile; 27 | std::ifstream fShaderFile; 28 | std::ifstream gShaderFile; 29 | // ensure ifstream objects can throw exceptions: 30 | vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); 31 | fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); 32 | gShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); 33 | try 34 | { 35 | // open files 36 | vShaderFile.open(vertexPath); 37 | fShaderFile.open(fragmentPath); 38 | std::stringstream vShaderStream, fShaderStream; 39 | // read file's buffer contents into streams 40 | vShaderStream << vShaderFile.rdbuf(); 41 | fShaderStream << fShaderFile.rdbuf(); 42 | // close file handlers 43 | vShaderFile.close(); 44 | fShaderFile.close(); 45 | // convert stream into string 46 | vertexCode = vShaderStream.str(); 47 | fragmentCode = fShaderStream.str(); 48 | // if geometry shader path is present, also load a geometry shader 49 | if(geometryPath != nullptr) 50 | { 51 | gShaderFile.open(geometryPath); 52 | std::stringstream gShaderStream; 53 | gShaderStream << gShaderFile.rdbuf(); 54 | gShaderFile.close(); 55 | geometryCode = gShaderStream.str(); 56 | } 57 | } 58 | // catch (std::ifstream::failure e) 59 | catch (...) 60 | { 61 | std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl; 62 | exit(1); 63 | } 64 | const char* vShaderCode = vertexCode.c_str(); 65 | const char * fShaderCode = fragmentCode.c_str(); 66 | // 2. compile shaders 67 | unsigned int vertex, fragment; 68 | // vertex shader 69 | vertex = glCreateShader(GL_VERTEX_SHADER); 70 | glShaderSource(vertex, 1, &vShaderCode, NULL); 71 | glCompileShader(vertex); 72 | checkCompileErrors(vertex, "VERTEX"); 73 | // fragment Shader 74 | fragment = glCreateShader(GL_FRAGMENT_SHADER); 75 | glShaderSource(fragment, 1, &fShaderCode, NULL); 76 | glCompileShader(fragment); 77 | checkCompileErrors(fragment, "FRAGMENT"); 78 | // if geometry shader is given, compile geometry shader 79 | unsigned int geometry = 0; 80 | if(geometryPath != nullptr) 81 | { 82 | const char * gShaderCode = geometryCode.c_str(); 83 | geometry = glCreateShader(GL_GEOMETRY_SHADER); 84 | glShaderSource(geometry, 1, &gShaderCode, NULL); 85 | glCompileShader(geometry); 86 | checkCompileErrors(geometry, "GEOMETRY"); 87 | } 88 | // shader Program 89 | ID = glCreateProgram(); 90 | glAttachShader(ID, vertex); 91 | glAttachShader(ID, fragment); 92 | if(geometryPath != nullptr) 93 | glAttachShader(ID, geometry); 94 | glLinkProgram(ID); 95 | checkCompileErrors(ID, "PROGRAM"); 96 | // delete the shaders as they're linked into our program now and no longer necessery 97 | glDeleteShader(vertex); 98 | glDeleteShader(fragment); 99 | if(geometryPath != nullptr) 100 | glDeleteShader(geometry); 101 | 102 | } 103 | // activate the shader 104 | // ------------------------------------------------------------------------ 105 | void use() 106 | { 107 | glUseProgram(ID); 108 | } 109 | // utility uniform functions 110 | // ------------------------------------------------------------------------ 111 | void setBool(const std::string &name, bool value) const 112 | { 113 | glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value); 114 | } 115 | // ------------------------------------------------------------------------ 116 | void setInt(const std::string &name, int value) const 117 | { 118 | glUniform1i(glGetUniformLocation(ID, name.c_str()), value); 119 | } 120 | // ------------------------------------------------------------------------ 121 | void setFloat(const std::string &name, float value) const 122 | { 123 | glUniform1f(glGetUniformLocation(ID, name.c_str()), value); 124 | } 125 | // ------------------------------------------------------------------------ 126 | void setVec2(const std::string &name, const glm::vec2 &value) const 127 | { 128 | glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); 129 | } 130 | void setVec2(const std::string &name, float x, float y) const 131 | { 132 | glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y); 133 | } 134 | // ------------------------------------------------------------------------ 135 | void setVec3(const std::string &name, const glm::vec3 &value) const 136 | { 137 | glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); 138 | } 139 | void setVec3(const std::string &name, float x, float y, float z) const 140 | { 141 | glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z); 142 | } 143 | // ------------------------------------------------------------------------ 144 | void setVec4(const std::string &name, const glm::vec4 &value) const 145 | { 146 | glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); 147 | } 148 | void setVec4(const std::string &name, float x, float y, float z, float w) 149 | { 150 | glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w); 151 | } 152 | // ------------------------------------------------------------------------ 153 | void setMat2(const std::string &name, const glm::mat2 &mat) const 154 | { 155 | glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); 156 | } 157 | // ------------------------------------------------------------------------ 158 | void setMat3(const std::string &name, const glm::mat3 &mat) const 159 | { 160 | glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); 161 | } 162 | // ------------------------------------------------------------------------ 163 | void setMat4(const std::string &name, const glm::mat4 &mat) const 164 | { 165 | glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); 166 | } 167 | 168 | private: 169 | // utility function for checking shader compilation/linking errors. 170 | // ------------------------------------------------------------------------ 171 | void checkCompileErrors(GLuint shader, std::string type) 172 | { 173 | GLint success; 174 | GLchar infoLog[1024]; 175 | if(type != "PROGRAM") 176 | { 177 | glGetShaderiv(shader, GL_COMPILE_STATUS, &success); 178 | if(!success) 179 | { 180 | glGetShaderInfoLog(shader, 1024, NULL, infoLog); 181 | std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; 182 | } 183 | } 184 | else 185 | { 186 | glGetProgramiv(shader, GL_LINK_STATUS, &success); 187 | if(!success) 188 | { 189 | glGetProgramInfoLog(shader, 1024, NULL, infoLog); 190 | std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; 191 | } 192 | } 193 | } 194 | }; 195 | #endif 196 | -------------------------------------------------------------------------------- /cratesan/README.md: -------------------------------------------------------------------------------- 1 | _Historical repo -- All development has moved here : https://github.com/nsauzede/cratesan_ 2 | 3 | # クレートさん (CrateSan, or MrCrate) 4 | A tribute to Sokoban by Thinking Rabbit, made in [Rust](Rust) and [V](V) languages, using SDL2 for multimedia. 5 | 6 | ![Screenshot of CrateSan](res/images/cratesan.png) 7 | 8 | # Try it 9 | In Rust : 10 | ``` 11 | $ cd Rust 12 | $ cargo run 13 | ``` 14 | 15 | In V : 16 | ``` 17 | $ cd V 18 | $ v run cratesan.v 19 | ``` 20 | 21 | # Controls 22 | - Arrows to move the player 23 | - Return to proceed to next level, when current is won 24 | - "R" to restart level 25 | 26 | # Credits 27 | All the levels are Copyright Thinking Rabbit, downloaded from this [URL](https://www.sourcecode.se/sokoban/levels?act=dnl_text&file=Original.slc). 28 | -------------------------------------------------------------------------------- /cratesan/Rust/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | $ Ignore copied *.dll files 13 | /*.dll 14 | -------------------------------------------------------------------------------- /cratesan/Rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cratesan" 3 | version = "0.1.0" 4 | authors = ["Nicolas Sauzede "] 5 | edition = "2018" 6 | build = "build.rs" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | rand = "0.7.*" 12 | 13 | [dependencies.sdl2] 14 | version = "0.34.*" 15 | default-features = false 16 | features = ["image", "ttf"] 17 | -------------------------------------------------------------------------------- /cratesan/Rust/README.md: -------------------------------------------------------------------------------- 1 | # Try it 2 | ``` 3 | $ cd Rust 4 | $ cargo run 5 | ``` 6 | 7 | # Build prerequisites for Windows 8 | On Linux, you only need to install standard SDL2 dev packages (search for that elsewhere on the web). 9 | 10 | On Windows, follow [the rust-sdl2 instructions](https://github.com/Rust-SDL2/rust-sdl2). 11 | At the end, you should have the folders "gnu-mingw" and "msvc" alongside this README.md, 12 | in order to build on Windows. 13 | -------------------------------------------------------------------------------- /cratesan/Rust/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::path::PathBuf; 3 | fn main() { 4 | let target = env::var("TARGET").unwrap(); 5 | if target.contains("pc-windows") { 6 | let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); 7 | let mut lib_dir = manifest_dir.clone(); 8 | let mut dll_dir = manifest_dir.clone(); 9 | if target.contains("msvc") { 10 | lib_dir.push("msvc"); 11 | dll_dir.push("msvc"); 12 | } else { 13 | lib_dir.push("gnu-mingw"); 14 | dll_dir.push("gnu-mingw"); 15 | } 16 | lib_dir.push("lib"); 17 | dll_dir.push("dll"); 18 | if target.contains("x86_64") { 19 | lib_dir.push("64"); 20 | dll_dir.push("64"); 21 | } else { 22 | lib_dir.push("32"); 23 | dll_dir.push("32"); 24 | } 25 | println!("cargo:rustc-link-search=all={}", lib_dir.display()); 26 | for entry in std::fs::read_dir(dll_dir).expect("Can't read DLL dir") { 27 | let entry_path = entry.expect("Invalid fs entry").path(); 28 | let file_name_result = entry_path.file_name(); 29 | let mut new_file_path = manifest_dir.clone(); 30 | if let Some(file_name) = file_name_result { 31 | let file_name = file_name.to_str().unwrap(); 32 | if file_name.ends_with(".dll") { 33 | new_file_path.push(file_name); 34 | std::fs::copy(&entry_path, new_file_path.as_path()) 35 | .expect("Can't copy from DLL dir"); 36 | } 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /cratesan/Rust/rustfmt.toml: -------------------------------------------------------------------------------- 1 | hard_tabs=true 2 | -------------------------------------------------------------------------------- /cratesan/Rust/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate sdl2; 2 | 3 | use sdl2::event::Event; 4 | use sdl2::image::{InitFlag, LoadTexture}; 5 | use sdl2::keyboard::Keycode; 6 | use sdl2::pixels::Color; 7 | use sdl2::rect::Rect; 8 | use sdl2::render::{Canvas, Texture, TextureCreator}; 9 | use sdl2::video::{Window, WindowContext}; 10 | 11 | use std::env::current_exe; 12 | use std::fs::File; 13 | use std::io::Read; 14 | use std::thread::sleep; 15 | use std::time::{Duration, SystemTime}; 16 | 17 | const ZOOM: usize = 2; 18 | const TEXT_SIZE: usize = 8; 19 | const TEXT_RATIO: usize = ZOOM; 20 | const WIDTH: usize = 320 * ZOOM; 21 | const HEIGHT: usize = 200 * ZOOM; 22 | const EMPTY: u8 = 0x0; 23 | const STORE: u8 = 0x1; 24 | const CRATE: u8 = 0x2; 25 | const WALL: u8 = 0x4; 26 | const C_EMPTY: char = ' '; 27 | const C_STORE: char = '.'; 28 | const C_STORED: char = '*'; 29 | const C_CRATE: char = '$'; 30 | const C_PLAYER: char = '@'; 31 | const C_SPLAYER: char = '&'; 32 | const C_WALL: char = '#'; 33 | const FONT_FILE: &str = "RobotoMono-Regular.ttf"; 34 | const LEVELS_FILE: &str = "levels.txt"; 35 | //const SCORES_FILE: &str = "scores.txt"; 36 | const I_EMPTY: &str = "empty.png"; 37 | const I_STORE: &str = "store.png"; 38 | const I_STORED: &str = "stored.png"; 39 | const I_CRATE: &str = "crate.png"; 40 | const I_PLAYER: &str = "player.png"; 41 | const I_SPLAYER: &str = "splayer.png"; 42 | const I_WALL: &str = "wall.png"; 43 | const N_EMPTY: usize = 0; 44 | const N_STORE: usize = 1; 45 | const N_STORED: usize = 2; 46 | const N_CRATE: usize = 3; 47 | const N_PLAYER: usize = 4; 48 | const N_SPLAYER: usize = 5; 49 | const N_WALL: usize = 6; 50 | const N_WHITE: usize = 7; 51 | 52 | type Map = Vec>; 53 | 54 | enum Status { 55 | Play, 56 | Pause, 57 | Win, 58 | } 59 | 60 | struct Level { 61 | map: Map, 62 | crates: u32, 63 | stored: u32, 64 | w: usize, 65 | h: usize, 66 | px: usize, 67 | py: usize, 68 | } 69 | 70 | struct UndoState { 71 | map: Option, // only store map if it changed during the move 72 | px: usize, 73 | py: usize, 74 | } 75 | 76 | struct Game<'ttf> { 77 | quit: bool, 78 | status: Status, 79 | must_draw: bool, 80 | levels: Vec, 81 | map: Map, 82 | undo_states: Vec, 83 | level: usize, 84 | moves: i32, 85 | pushes: i32, 86 | total_time_s: u32, 87 | last_ticks: SystemTime, 88 | // following are copies of current level's 89 | crates: u32, 90 | stored: u32, 91 | /// map dims 92 | w: usize, 93 | h: usize, 94 | /// player pos 95 | px: usize, 96 | py: usize, 97 | /// block dims 98 | bw: usize, 99 | bh: usize, 100 | // SDL 101 | width: usize, 102 | height: usize, 103 | // TTF 104 | font: sdl2::ttf::Font<'ttf, 'static>, 105 | } 106 | 107 | impl<'ttf> Game<'ttf> { 108 | fn load_levels() -> Vec { 109 | let root_dir = current_exe().unwrap(); 110 | let root_dir = root_dir 111 | .parent() 112 | .unwrap() 113 | .parent() 114 | .unwrap() 115 | .parent() 116 | .unwrap(); 117 | let parent_dir = root_dir.parent().unwrap(); 118 | let levels_file = parent_dir.join("res").join("levels").join(LEVELS_FILE); 119 | let levels_file = levels_file.to_str().unwrap(); 120 | let mut levels = Vec::new(); 121 | let mut vlevels = Vec::new(); 122 | let mut slevel = String::new(); 123 | let mut level = 1; 124 | let mut slevels = String::new(); 125 | let mut f = File::open(levels_file).unwrap(); 126 | f.read_to_string(&mut slevels).unwrap(); 127 | for line in slevels.lines() { 128 | if line.is_empty() { 129 | if !slevel.is_empty() { 130 | vlevels.push(slevel); 131 | slevel = "".to_string(); 132 | } 133 | continue; 134 | } 135 | if line.starts_with(';') { 136 | continue; 137 | } 138 | slevel = format!("{}\n{}", slevel, line); 139 | } 140 | if !slevel.is_empty() { 141 | vlevels.push(slevel); 142 | } 143 | for s in vlevels { 144 | let mut map = Vec::new(); 145 | let mut crates = 0; 146 | let mut stores = 0; 147 | let mut stored = 0; 148 | let mut w = 0; 149 | let mut h = 0; 150 | let mut px = 0; 151 | let mut py = 0; 152 | let mut player_found = false; 153 | for line in s.lines() { 154 | if line.len() > w { 155 | w = line.len(); 156 | } 157 | } 158 | for line in s.lines() { 159 | if line.is_empty() { 160 | continue; 161 | } 162 | let mut v = vec![EMPTY; w]; 163 | for (i, e) in line.chars().enumerate() { 164 | match e { 165 | C_EMPTY => { 166 | v[i] = EMPTY; 167 | } 168 | C_STORE => { 169 | v[i] = STORE; 170 | stores += 1; 171 | } 172 | C_CRATE => { 173 | v[i] = CRATE; 174 | crates += 1; 175 | } 176 | C_STORED => { 177 | v[i] = CRATE | STORE; 178 | stores += 1; 179 | crates += 1; 180 | stored += 1; 181 | } 182 | C_PLAYER => { 183 | if player_found { 184 | panic!("Player found multiple times in level {}", level); 185 | }; 186 | px = i; 187 | py = h; 188 | player_found = true; 189 | v[i] = EMPTY; 190 | } 191 | C_SPLAYER => { 192 | if player_found { 193 | panic!("Player found multiple times in level {}", level); 194 | }; 195 | px = i; 196 | py = h; 197 | player_found = true; 198 | v[i] = STORE; 199 | stores += 1; 200 | } 201 | C_WALL => { 202 | v[i] = WALL; 203 | } 204 | _ => { 205 | panic!("Invalid element [{}] in level", e); 206 | } 207 | } 208 | } 209 | map.push(v); 210 | h += 1; 211 | } 212 | if crates != stores { 213 | panic!( 214 | "Mismatch between crates={} and stores={} in level", 215 | crates, stores 216 | ); 217 | } 218 | if !player_found { 219 | panic!("Player not found in level {}", level); 220 | } else { 221 | } 222 | levels.push(Level { 223 | map, 224 | crates, 225 | stored, 226 | w, 227 | h, 228 | px, 229 | py, 230 | }); 231 | level += 1; 232 | } 233 | levels 234 | } 235 | 236 | fn new( 237 | ttf_context: &'ttf sdl2::ttf::Sdl2TtfContext, 238 | root_dir: &std::path::Path, 239 | width: usize, 240 | height: usize, 241 | ) -> Game<'ttf> { 242 | let levels = Game::load_levels(); 243 | let ttf_file = root_dir.join("res").join("fonts").join(FONT_FILE); 244 | let font = ttf_context 245 | .load_font(ttf_file, (TEXT_SIZE * TEXT_RATIO) as u16) 246 | .expect("Couldn't load the font"); 247 | 248 | let mut g = Game { 249 | quit: false, 250 | status: Status::Play, 251 | must_draw: true, 252 | levels, 253 | map: Vec::new(), 254 | undo_states: Vec::new(), 255 | level: 0, 256 | moves: 0, 257 | pushes: 0, 258 | total_time_s: 0, 259 | last_ticks: SystemTime::now(), 260 | crates: 0, 261 | stored: 0, 262 | w: 0, 263 | h: 0, 264 | px: 0, 265 | py: 0, 266 | bw: 0, 267 | bh: 0, 268 | width, 269 | height, 270 | font, 271 | }; 272 | g.set_level(0); 273 | g 274 | } 275 | 276 | fn set_level(&mut self, level: usize) -> bool { 277 | if level < self.levels.len() { 278 | self.status = Status::Play; 279 | self.must_draw = true; 280 | self.level = level; 281 | self.moves = 0; 282 | self.pushes = 0; 283 | self.total_time_s = 0; 284 | self.map = self.levels[level].map.clone(); 285 | self.undo_states = Vec::new(); 286 | self.crates = self.levels[level].crates; 287 | self.stored = self.levels[level].stored; 288 | self.w = self.levels[level].w; 289 | self.h = self.levels[level].h; 290 | self.px = self.levels[level].px; 291 | self.py = self.levels[level].py; 292 | self.bw = self.width / self.w; 293 | self.bh = (self.height - TEXT_SIZE * TEXT_RATIO) / self.h; 294 | true 295 | } else { 296 | false 297 | } 298 | } 299 | 300 | fn can_move(&self, x: usize, y: usize) -> bool { 301 | if x < self.w && y < self.h { 302 | let e = self.map[y][x]; 303 | if e == EMPTY || e == STORE { 304 | return true; 305 | } 306 | } 307 | false 308 | } 309 | 310 | /// Try to move to x+dx:y+dy and also push to x+2dx:y+2dy 311 | fn try_move(&mut self, dx: isize, dy: isize) { 312 | let mut do_it = false; 313 | let x = self.px as isize + dx; 314 | let y = self.py as isize + dy; 315 | if x < 0 || y < 0 { 316 | return; 317 | } 318 | let x = x as usize; 319 | let y = y as usize; 320 | if x >= self.w || y >= self.h { 321 | return; 322 | } 323 | let mut map = None; 324 | if self.map[y][x] & CRATE == CRATE { 325 | let to_x = (x as isize + dx) as usize; 326 | let to_y = (y as isize + dy) as usize; 327 | if self.can_move(to_x, to_y) { 328 | self.pushes += 1; 329 | map = Some(self.map.clone()); 330 | self.map[y][x] &= !CRATE; 331 | if self.map[y][x] & STORE == STORE { 332 | self.stored -= 1; 333 | } 334 | self.map[to_y][to_x] |= CRATE; 335 | if self.map[to_y][to_x] & STORE == STORE { 336 | self.stored += 1; 337 | if self.stored == self.crates { 338 | self.status = Status::Win; 339 | } 340 | } 341 | do_it = true; 342 | } 343 | } else { 344 | do_it = self.can_move(x, y); 345 | } 346 | if do_it { 347 | self.undo_states.push(UndoState { 348 | map, 349 | px: self.px, 350 | py: self.py, 351 | }); 352 | self.moves += 1; 353 | self.px = x; 354 | self.py = y; 355 | self.must_draw = true; 356 | } 357 | } 358 | 359 | fn draw_map( 360 | &mut self, 361 | canvas: &mut sdl2::render::Canvas, 362 | textures: &[sdl2::render::Texture<'_>], 363 | texture_creator: &sdl2::render::TextureCreator, 364 | ) { 365 | let curr_ticks = SystemTime::now(); 366 | let duration = curr_ticks 367 | .duration_since(self.last_ticks) 368 | .unwrap() 369 | .as_millis(); 370 | if duration > 1000 { 371 | if let Status::Play = self.status { 372 | self.total_time_s += (duration / 1000) as u32; 373 | } 374 | self.last_ticks = curr_ticks; 375 | self.must_draw = true; 376 | } 377 | if self.must_draw { 378 | canvas.set_draw_color(Color::RGB(0, 0, 0)); 379 | canvas.clear(); 380 | // bottom status bar 381 | canvas 382 | .copy( 383 | &textures[N_WHITE], 384 | None, 385 | Rect::new( 386 | 0, 387 | (self.height - TEXT_SIZE * TEXT_RATIO) as i32, 388 | self.width as u32, 389 | (TEXT_SIZE * TEXT_RATIO) as u32, 390 | ), 391 | ) 392 | .expect("Couldn't copy texture into window"); 393 | let x = (WIDTH - self.w * self.bw) / 2; 394 | let y = 0; 395 | for (j, line) in self.map.iter().enumerate() { 396 | for (i, &e) in line.iter().enumerate() { 397 | let idx = if e == EMPTY { 398 | if self.px == i && self.py == j { 399 | N_PLAYER 400 | } else { 401 | N_EMPTY 402 | } 403 | } else if e == STORE { 404 | if self.px == i && self.py == j { 405 | N_SPLAYER 406 | } else { 407 | N_STORE 408 | } 409 | } else if e == CRATE { 410 | N_CRATE 411 | } else if e == WALL { 412 | N_WALL 413 | } else if e == CRATE | STORE { 414 | N_STORED 415 | } else { 416 | N_EMPTY 417 | }; 418 | canvas 419 | .copy( 420 | &textures[idx as usize], 421 | None, 422 | Rect::new( 423 | (x + i * self.bw) as i32, 424 | (y + j * self.bh) as i32, 425 | self.bw as u32, 426 | self.bh as u32, 427 | ), 428 | ) 429 | .expect("Couldn't copy texture into window"); 430 | } 431 | } 432 | let state = match self.status { 433 | Status::Win => "You win! Press Return..", 434 | Status::Pause => "*PAUSE* Press Space..", 435 | _ => "", 436 | }; 437 | let ts = self.total_time_s % 60; 438 | let tm = (self.total_time_s / 60) % 60; 439 | let th = self.total_time_s / 3600; 440 | let text = format!( 441 | "{:02}| moves: {:04} pushes: {:04} time:{}:{:02}:{:02} {}", 442 | self.level + 1, 443 | self.moves, 444 | self.pushes, 445 | th, 446 | tm, 447 | ts, 448 | state 449 | ); 450 | let texture = create_texture_from_text(texture_creator, &self.font, &text, 0, 0, 0) 451 | .expect("Cannot render text"); 452 | canvas 453 | .copy( 454 | &texture, 455 | None, 456 | Some(Rect::new( 457 | 0, 458 | (self.height - TEXT_SIZE * TEXT_RATIO - 4) as i32, 459 | (text.len() * 5 * ZOOM) as u32, 460 | (12 * ZOOM) as u32, 461 | )), 462 | ) 463 | .expect("Couldn't copy text"); 464 | canvas.present(); 465 | self.must_draw = false; 466 | } 467 | } 468 | 469 | fn handle_events(&mut self, event_pump: &mut sdl2::EventPump) { 470 | for event in event_pump.poll_iter() { 471 | if !match self.status { 472 | Status::Play => self.handle_event_play(event), 473 | Status::Pause => self.handle_event_pause(event), 474 | Status::Win => self.handle_event_win(event), 475 | } { 476 | break; 477 | } 478 | } 479 | } 480 | 481 | fn handle_event_play(&mut self, event: sdl2::event::Event) -> bool { 482 | let mut cont = true; 483 | match event { 484 | Event::Quit { .. } => { 485 | self.quit = true; 486 | cont = false; 487 | } 488 | Event::KeyDown { 489 | keycode: Some(k), .. 490 | } => match k { 491 | Keycode::Escape => { 492 | self.quit = true; 493 | cont = false; 494 | } 495 | Keycode::Space => { 496 | self.status = Status::Pause; 497 | self.must_draw = true; 498 | cont = false; 499 | } 500 | Keycode::R => { 501 | self.set_level(self.level); 502 | cont = false; 503 | } 504 | Keycode::W => { 505 | self.status = Status::Win; 506 | self.must_draw = true; 507 | cont = false; 508 | } 509 | Keycode::U => { 510 | if let Some(state) = self.undo_states.pop() { 511 | if let Some(map) = state.map { 512 | self.pushes -= 1; 513 | self.map = map; 514 | } 515 | self.moves -= 1; 516 | self.px = state.px; 517 | self.py = state.py; 518 | self.must_draw = true; 519 | } 520 | } 521 | Keycode::Up => { 522 | self.try_move(0, -1); 523 | } 524 | Keycode::Down => { 525 | self.try_move(0, 1); 526 | } 527 | Keycode::Left => { 528 | self.try_move(-1, 0); 529 | } 530 | Keycode::Right => { 531 | self.try_move(1, 0); 532 | } 533 | _ => {} 534 | }, 535 | _ => {} 536 | } 537 | cont 538 | } 539 | 540 | fn handle_event_pause(&mut self, event: sdl2::event::Event) -> bool { 541 | let mut cont = true; 542 | match event { 543 | Event::Quit { .. } => { 544 | self.quit = true; 545 | cont = false; 546 | } 547 | Event::KeyDown { 548 | keycode: Some(k), .. 549 | } => match k { 550 | Keycode::Escape => { 551 | self.quit = true; 552 | cont = false; 553 | } 554 | Keycode::Space => { 555 | self.status = Status::Play; 556 | self.must_draw = true; 557 | cont = false; 558 | } 559 | _ => {} 560 | }, 561 | _ => {} 562 | } 563 | cont 564 | } 565 | 566 | fn handle_event_win(&mut self, event: sdl2::event::Event) -> bool { 567 | let mut cont = true; 568 | match event { 569 | Event::Quit { .. } => { 570 | self.quit = true; 571 | cont = false; 572 | } 573 | Event::KeyDown { 574 | keycode: Some(k), .. 575 | } => match k { 576 | Keycode::Escape => { 577 | self.quit = true; 578 | cont = false; 579 | } 580 | Keycode::Return => { 581 | if self.set_level(self.level + 1) { 582 | } else { 583 | println!("Game over."); 584 | self.quit = true; 585 | cont = false; 586 | } 587 | } 588 | Keycode::R => { 589 | self.set_level(self.level); 590 | cont = false; 591 | } 592 | _ => {} 593 | }, 594 | _ => {} 595 | } 596 | cont 597 | } 598 | 599 | fn sleep(&self) { 600 | sleep(Duration::new(0, 1_000_000_000u32 / 60)); 601 | } 602 | } 603 | 604 | fn create_texture_from_text<'a>( 605 | texture_creator: &'a TextureCreator, 606 | font: &sdl2::ttf::Font, 607 | text: &str, 608 | r: u8, 609 | g: u8, 610 | b: u8, 611 | ) -> Option> { 612 | if let Ok(surface) = font.render(text).blended(Color::RGB(r, g, b)) { 613 | texture_creator.create_texture_from_surface(&surface).ok() 614 | } else { 615 | None 616 | } 617 | } 618 | 619 | fn create_texture_rect<'a>( 620 | canvas: &mut Canvas, 621 | texture_creator: &'a TextureCreator, 622 | r: u8, 623 | g: u8, 624 | b: u8, 625 | width: u32, 626 | height: u32, 627 | ) -> Option> { 628 | if let Ok(mut square_texture) = texture_creator.create_texture_target(None, width, height) { 629 | canvas 630 | .with_texture_canvas(&mut square_texture, |texture| { 631 | texture.set_draw_color(Color::RGB(r, g, b)); 632 | texture.clear(); 633 | }) 634 | .expect("Failed to color a texture"); 635 | Some(square_texture) 636 | } else { 637 | None 638 | } 639 | } 640 | 641 | fn load_texture<'a>( 642 | root_dir: &std::path::Path, 643 | texture_creator: &'a TextureCreator, 644 | file: &str, 645 | ) -> Option> { 646 | let file = root_dir.join("res").join("images").join(file); 647 | let file = file.to_str().unwrap(); 648 | Some(texture_creator.load_texture(file).unwrap()) 649 | } 650 | 651 | fn main() { 652 | let title = "クレートさん Rust"; 653 | let width = WIDTH; 654 | let height = HEIGHT; 655 | let sdl_context = sdl2::init().expect("SDL initialization failed"); 656 | let ttf_context = sdl2::ttf::init().expect("SDL TTF initialization failed"); 657 | let _image_context = sdl2::image::init(InitFlag::PNG).unwrap(); 658 | let video_subsystem = sdl_context 659 | .video() 660 | .expect("Couldn't get SDL video subsystem"); 661 | let window = video_subsystem 662 | .window(title, width as u32, height as u32) 663 | .position_centered() 664 | .build() 665 | .expect("Failed to create window"); 666 | let mut canvas = window 667 | .into_canvas() 668 | .target_texture() 669 | .present_vsync() 670 | .build() 671 | .expect("Couldn't get window's canvas"); 672 | let mut event_pump = sdl_context.event_pump().expect( 673 | "Failed to get 674 | SDL event pump", 675 | ); 676 | let texture_creator: TextureCreator<_> = canvas.texture_creator(); 677 | let root_dir = current_exe().unwrap(); 678 | let root_dir = root_dir 679 | .parent() 680 | .unwrap() 681 | .parent() 682 | .unwrap() 683 | .parent() 684 | .unwrap() 685 | .parent() 686 | .unwrap(); 687 | let mut game = Game::new(&ttf_context, root_dir, width, height); 688 | macro_rules! texture { 689 | ($r:expr, $g:expr, $b:expr) => { 690 | create_texture_rect( 691 | &mut canvas, 692 | &texture_creator, 693 | $r, 694 | $g, 695 | $b, 696 | game.bw as u32, 697 | game.bh as u32, 698 | ) 699 | .unwrap() 700 | }; 701 | ($file:expr) => { 702 | load_texture(root_dir, &texture_creator, $file).unwrap() 703 | }; 704 | } 705 | let textures = [ 706 | texture!(I_EMPTY), 707 | texture!(I_STORE), 708 | texture!(I_STORED), 709 | texture!(I_CRATE), 710 | texture!(I_PLAYER), 711 | texture!(I_SPLAYER), 712 | texture!(I_WALL), 713 | texture!(255, 255, 255), 714 | ]; 715 | while !game.quit { 716 | game.handle_events(&mut event_pump); 717 | game.draw_map(&mut canvas, &textures, &texture_creator); 718 | game.sleep(); 719 | } 720 | } 721 | -------------------------------------------------------------------------------- /cratesan/V/README.md: -------------------------------------------------------------------------------- 1 | # Try it 2 | In V : 3 | ``` 4 | $ cd V 5 | $ v run cratesan.v 6 | ``` 7 | -------------------------------------------------------------------------------- /cratesan/V/cratesan.v: -------------------------------------------------------------------------------- 1 | import nsauzede.vsdl2 2 | import nsauzede.vsdl2.image as img 3 | import os 4 | 5 | const ( 6 | zoom = 2 7 | text_size = 8 8 | text_ratio = zoom 9 | white = vsdl2.Color{255, 255, 255, 0} 10 | black = vsdl2.Color{0, 0, 0, 0} 11 | text_color = black 12 | width = 320 * zoom 13 | height = 200 * zoom 14 | empty = 0x0 15 | store = 0x1 16 | crate = 0x2 17 | wall = 0x4 18 | c_empty = ` ` 19 | c_store = `.` 20 | c_stored = `*` 21 | c_crate = `$` 22 | c_player = `@` 23 | c_splayer = `&` 24 | c_wall = `#` 25 | bpp = 32 26 | res_dir = os.resource_abs_path('../res') 27 | font_file = res_dir + '/fonts/RobotoMono-Regular.ttf' 28 | levels_file = res_dir + '/levels/levels.txt' 29 | base_dir = os.dir(os.real_path(os.executable())) 30 | scores_file = base_dir + '/scores.txt' 31 | i_empty = res_dir + '/images/empty.png' 32 | i_store = res_dir + '/images/store.png' 33 | i_stored = res_dir + '/images/stored.png' 34 | i_crate = res_dir + '/images/crate.png' 35 | i_player = res_dir + '/images/player.png' 36 | i_splayer = res_dir + '/images/splayer.png' 37 | i_wall = res_dir + '/images/wall.png' 38 | n_empty = 0 39 | n_store = 1 40 | n_stored = 2 41 | n_crate = 3 42 | n_player = 4 43 | n_splayer = 5 44 | n_wall = 6 45 | ) 46 | 47 | enum Status { 48 | play 49 | pause 50 | win 51 | } 52 | 53 | struct Level { 54 | crates int // number of crates 55 | mut: 56 | w int // map dims 57 | h int // map dims 58 | map [][]byte // map 59 | stored int // number of stored crates 60 | px int // player pos 61 | py int // player pos 62 | } 63 | 64 | struct Score { 65 | mut: 66 | level int 67 | pushes int 68 | moves int 69 | time_s u32 70 | } 71 | 72 | struct Snapshot { 73 | mut: 74 | state State 75 | undo_states []State 76 | } 77 | 78 | struct State { 79 | mut: 80 | map [][]byte // TODO : make it an option ? (ie: map ?[][]byte) -- seems broken rn 81 | stored int 82 | px int 83 | py int 84 | time_s u32 85 | pushes int 86 | moves int 87 | undos int 88 | } 89 | 90 | struct Game { 91 | title string 92 | mut: 93 | quit bool 94 | status Status 95 | must_draw bool 96 | // Game levels 97 | levels []Level 98 | level int // current level 99 | snapshots []Snapshot // saved snapshots (currently only one max) 100 | snap Snapshot // current snapshot : state + undo_states 101 | last_ticks u32 102 | scores []Score 103 | debug bool 104 | bw int // block dims 105 | bh int // block dims 106 | // SDL stuff 107 | window voidptr 108 | renderer voidptr 109 | screen &vsdl2.Surface 110 | texture voidptr 111 | width int 112 | height int 113 | block_surf []&vsdl2.Surface 114 | block_text []voidptr 115 | // TTF 116 | font voidptr 117 | } 118 | 119 | fn (g Game) save_state(mut state State, full bool) { 120 | unsafe { 121 | *state = g.snap.state 122 | } 123 | mut map := [][]byte{} 124 | if full { 125 | map = g.snap.state.map.clone() 126 | } 127 | state.map = map 128 | } 129 | 130 | fn (mut g Game) restore_state(state State) { 131 | map := g.snap.state.map 132 | g.snap.state = state 133 | if state.map.len == 0 { 134 | g.snap.state.map = map 135 | } 136 | if g.status == .win { // remove current level score, if win 137 | for i, score in g.scores { 138 | if score.level == g.level { 139 | println('deleting score $i : $score') 140 | g.scores.delete(i) 141 | } 142 | } 143 | } 144 | } 145 | 146 | fn (mut g Game) save_snapshot() { 147 | g.snapshots = []Snapshot{} // limit snapshots depth to 1 148 | g.snapshots << Snapshot{ 149 | undo_states: g.snap.undo_states.clone() 150 | } 151 | g.save_state(mut g.snapshots[0].state, true) 152 | g.debug_dump() 153 | } 154 | 155 | fn (mut g Game) load_snapshot() { 156 | if g.snapshots.len > 0 { 157 | snap := g.snapshots.pop() 158 | g.snap.undo_states = snap.undo_states 159 | g.restore_state(snap.state) 160 | g.must_draw = true 161 | save_scores(g.scores) 162 | g.save_snapshot() // limit snapshots depth to 1 163 | } 164 | } 165 | 166 | fn (mut g Game) pop_undo() { 167 | if g.snap.undo_states.len > 0 { 168 | state := g.snap.undo_states.pop() 169 | g.restore_state(state) 170 | g.must_draw = true 171 | save_scores(g.scores) 172 | g.snap.state.undos++ 173 | g.debug_dump() 174 | } 175 | } 176 | 177 | fn (mut g Game) push_undo(full bool) { 178 | mut state := State{} 179 | g.save_state(mut state, full) 180 | g.snap.undo_states << state 181 | } 182 | 183 | fn (mut g Game) can_move(x, y int) bool { 184 | if x < g.levels[g.level].w && y < g.levels[g.level].h { 185 | e := g.snap.state.map[y][x] 186 | if e == empty || e == store { 187 | return true 188 | } 189 | } 190 | return false 191 | } 192 | 193 | // Try to move to x+dx:y+dy and also push to x+2dx:y+2dy 194 | fn (mut g Game) try_move(dx, dy int) bool { 195 | mut do_it := false 196 | x := g.snap.state.px + dx 197 | y := g.snap.state.py + dy 198 | if g.snap.state.map[y][x] & crate == crate { 199 | to_x := x + dx 200 | to_y := y + dy 201 | if g.can_move(to_x, to_y) { 202 | do_it = true 203 | g.push_undo(true) 204 | g.snap.state.pushes++ 205 | g.snap.state.map[y][x] &= ~crate 206 | if g.snap.state.map[y][x] & store == store { 207 | g.snap.state.stored-- 208 | } 209 | g.snap.state.map[to_y][to_x] |= crate 210 | if g.snap.state.map[to_y][to_x] & store == store { 211 | g.snap.state.stored++ 212 | if g.snap.state.stored == g.levels[g.level].crates { 213 | g.status = .win 214 | g.save_score() 215 | save_scores(g.scores) 216 | } 217 | } 218 | } 219 | } else { 220 | do_it = g.can_move(x, y) 221 | if do_it { 222 | g.push_undo(false) 223 | } 224 | } 225 | if do_it { 226 | g.snap.state.moves++ 227 | g.snap.state.px = x 228 | g.snap.state.py = y 229 | g.must_draw = true 230 | g.debug_dump() 231 | } 232 | return do_it 233 | } 234 | 235 | fn (g Game) debug_dump() { 236 | if g.debug { 237 | println('level=$g.level crates=$g.snap.state.stored/$g.levels[g.level].crates moves=$g.snap.state.moves pushes=$g.snap.state.pushes undos=$g.snap.state.undos/$g.snap.undo_states.len snaps=$g.snapshots.len time=$g.snap.state.time_s') 238 | } 239 | } 240 | 241 | fn load_levels() []Level { 242 | mut levels := []Level{} 243 | mut vlevels := []string{} 244 | mut slevel := '' 245 | slevels := os.read_file(levels_file.trim_space()) or { 246 | panic('Failed to open levels file') 247 | } 248 | for line in slevels.split_into_lines() { 249 | if line.len == 0 { 250 | if slevel.len > 0 { 251 | vlevels << slevel 252 | slevel = '' 253 | } 254 | continue 255 | } 256 | if line.starts_with(';') { 257 | continue 258 | } 259 | slevel = slevel + '\n' + line 260 | } 261 | if slevel.len > 0 { 262 | vlevels << slevel 263 | } 264 | for s in vlevels { 265 | mut map := [][]byte{} 266 | mut crates := 0 267 | mut stores := 0 268 | mut stored := 0 269 | mut w := 0 270 | mut h := 0 271 | mut px := 0 272 | mut py := 0 273 | mut player_found := false 274 | for line in s.split_into_lines() { 275 | if line.len > w { 276 | w = line.len 277 | } 278 | } 279 | for line in s.split_into_lines() { 280 | if line.len == 0 { 281 | continue 282 | } 283 | mut v := [byte(empty)].repeat(w) 284 | for i, e in line { 285 | match e { 286 | c_empty { 287 | v[i] = empty 288 | } 289 | c_store { 290 | v[i] = store 291 | stores++ 292 | } 293 | c_crate { 294 | v[i] = crate 295 | crates++ 296 | } 297 | c_stored { 298 | v[i] = crate | store 299 | stores++ 300 | crates++ 301 | stored++ 302 | } 303 | c_player { 304 | if player_found { 305 | panic('Player found multiple times in level') 306 | } 307 | px = i 308 | py = h 309 | player_found = true 310 | v[i] = empty 311 | } 312 | c_splayer { 313 | if player_found { 314 | panic('Player found multiple times in level') 315 | } 316 | px = i 317 | py = h 318 | player_found = true 319 | v[i] = store 320 | stores++ 321 | } 322 | c_wall { 323 | v[i] = wall 324 | } 325 | else { 326 | panic('Invalid element [$e.str()] in level') 327 | } 328 | } 329 | } 330 | map << v 331 | h++ 332 | } 333 | if crates != stores { 334 | panic('Mismatch between crates=$crates and stores=$stores in level') 335 | } 336 | if !player_found { 337 | panic('Player not found in level') 338 | } 339 | levels << Level{ 340 | map: map 341 | crates: crates 342 | stored: stored 343 | w: w 344 | h: h 345 | px: px 346 | py: py 347 | } 348 | } 349 | return levels 350 | } 351 | 352 | fn (mut g Game) set_level(level int) bool { 353 | if level < g.levels.len { 354 | g.status = .play 355 | g.must_draw = true 356 | g.level = level 357 | g.snap = Snapshot{ 358 | state: State{ 359 | map: g.levels[g.level].map.clone() 360 | } 361 | } 362 | g.snap.undo_states = []State{} 363 | g.snap.state.undos = 0 364 | g.snapshots = []Snapshot{} 365 | g.snap.state.stored = g.levels[g.level].stored 366 | g.levels[g.level].w = g.levels[g.level].w 367 | g.levels[g.level].h = g.levels[g.level].h 368 | g.snap.state.moves = 0 369 | g.snap.state.pushes = 0 370 | g.snap.state.time_s = 0 371 | g.last_ticks = vsdl2.get_ticks() 372 | g.snap.state.px = g.levels[g.level].px 373 | g.snap.state.py = g.levels[g.level].py 374 | g.bw = g.width / g.levels[g.level].w 375 | g.bh = (g.height - text_size * text_ratio) / g.levels[g.level].h 376 | g.debug_dump() 377 | return true 378 | } else { 379 | return false 380 | } 381 | } 382 | 383 | fn (mut g Game) load_tex(file string) { 384 | surf := img.load(file) 385 | if !isnil(surf) { 386 | g.block_surf << surf 387 | tex := vsdl2.create_texture_from_surface(g.renderer, surf) 388 | if !isnil(tex) { 389 | g.block_text << tex 390 | } 391 | } 392 | } 393 | 394 | fn (mut g Game) delete() { 395 | save_scores(g.scores) 396 | for t in g.block_text { 397 | if !isnil(t) { 398 | vsdl2.destroy_texture(t) 399 | } 400 | } 401 | for s in g.block_surf { 402 | if !isnil(s) { 403 | vsdl2.free_surface(s) 404 | } 405 | } 406 | if !isnil(g.font) { 407 | C.TTF_CloseFont(g.font) 408 | } 409 | } 410 | 411 | fn load_scores() []Score { 412 | mut ret := []Score{} 413 | s := os.read_file_array(scores_file) 414 | if s.len > 0 { 415 | ret = s 416 | } 417 | return ret 418 | } 419 | 420 | fn (mut g Game) save_score() { 421 | mut push_score := true 422 | for score in g.scores { 423 | if score.level == g.level { 424 | push_score = false 425 | } 426 | } 427 | if push_score { 428 | s := Score{ 429 | level: g.level 430 | pushes: g.snap.state.pushes 431 | moves: g.snap.state.moves 432 | time_s: g.snap.state.time_s 433 | } 434 | g.scores << s 435 | } 436 | } 437 | 438 | fn save_scores(scores []Score) { 439 | if scores.len > 0 { 440 | os.write_file_array(scores_file, scores) 441 | } else { 442 | os.rm(scores_file) 443 | } 444 | } 445 | 446 | fn new_game(title string) Game { 447 | levels := load_levels() 448 | scores := load_scores() 449 | mut g := Game{ 450 | title: title 451 | quit: false 452 | status: .play 453 | must_draw: true 454 | levels: levels 455 | scores: scores 456 | debug: false 457 | screen: 0 458 | font: 0 459 | } 460 | C.SDL_Init(C.SDL_INIT_VIDEO) 461 | C.atexit(C.SDL_Quit) 462 | C.TTF_Init() 463 | C.atexit(C.TTF_Quit) 464 | vsdl2.create_window_and_renderer(width, height, 0, &g.window, &g.renderer) 465 | C.SDL_SetWindowTitle(g.window, g.title.str) 466 | g.screen = vsdl2.create_rgb_surface(0, width, height, bpp, 0x00FF0000, 0x0000FF00, 467 | 0x000000FF, 0xFF000000) 468 | g.texture = C.SDL_CreateTexture(g.renderer, C.SDL_PIXELFORMAT_ARGB8888, C.SDL_TEXTUREACCESS_STREAMING, 469 | width, height) 470 | g.font = C.TTF_OpenFont(font_file.str, text_size * text_ratio) 471 | g.width = width 472 | g.height = height 473 | mut dones := [false].repeat(levels.len) 474 | for score in scores { 475 | if score.level >= 0 && score.level < levels.len { 476 | dones[score.level] = true 477 | } 478 | } 479 | mut level := 0 480 | for done in dones { 481 | if !done { 482 | break 483 | } 484 | level++ 485 | } 486 | g.set_level(level) 487 | g.load_tex(i_empty) 488 | g.load_tex(i_store) 489 | g.load_tex(i_stored) 490 | g.load_tex(i_crate) 491 | g.load_tex(i_player) 492 | g.load_tex(i_splayer) 493 | g.load_tex(i_wall) 494 | return g 495 | } 496 | 497 | fn (g &Game) draw_text(x, y int, text string, tcol vsdl2.Color) { 498 | if !isnil(g.font) { 499 | tcol_ := C.SDL_Color{tcol.r, tcol.g, tcol.b, tcol.a} 500 | tsurf := C.TTF_RenderText_Solid(g.font, text.str, tcol_) 501 | ttext := C.SDL_CreateTextureFromSurface(g.renderer, tsurf) 502 | texw := 0 503 | texh := 0 504 | C.SDL_QueryTexture(ttext, 0, 0, &texw, &texh) 505 | dstrect := vsdl2.Rect{x, y, texw, texh} 506 | vsdl2.render_copy(g.renderer, ttext, voidptr(0), &dstrect) 507 | C.SDL_DestroyTexture(ttext) 508 | vsdl2.free_surface(tsurf) 509 | } 510 | } 511 | 512 | fn (mut g Game) draw_map() { 513 | curr_ticks := vsdl2.get_ticks() 514 | if curr_ticks > g.last_ticks + 1000 { 515 | if g.status == .play { 516 | g.snap.state.time_s += (curr_ticks - g.last_ticks) / 1000 517 | } 518 | g.last_ticks = curr_ticks 519 | g.must_draw = true 520 | } 521 | if g.must_draw { 522 | C.SDL_RenderClear(g.renderer) 523 | mut rect := vsdl2.Rect{0, 0, g.width, g.height} 524 | mut col := vsdl2.Color{byte(0), byte(0), byte(0), byte(255)} 525 | vsdl2.fill_rect(g.screen, &rect, col) 526 | // bottom status bar 527 | rect = vsdl2.Rect{0, height - text_size * text_ratio, g.width, text_size * text_ratio} 528 | vsdl2.fill_rect(g.screen, &rect, white) 529 | C.SDL_UpdateTexture(g.texture, 0, g.screen.pixels, g.screen.pitch) 530 | C.SDL_RenderCopy(g.renderer, g.texture, voidptr(0), voidptr(0)) 531 | x := (width - g.levels[g.level].w * g.bw) / 2 532 | y := 0 533 | for j, line in g.snap.state.map { 534 | for i, e in line { 535 | rect = vsdl2.Rect{x + i * g.bw, y + j * g.bh, g.bw, g.bh} 536 | tex := match e { 537 | empty { 538 | if g.snap.state.px == i && g.snap.state.py == j { g.block_text[n_player] } else { g.block_text[n_empty] } 539 | } 540 | store { 541 | if g.snap.state.px == i && g.snap.state.py == j { g.block_text[n_splayer] } else { g.block_text[n_store] } 542 | } 543 | crate { 544 | g.block_text[n_crate] 545 | } 546 | wall { 547 | g.block_text[n_wall] 548 | } 549 | crate | store { 550 | g.block_text[n_stored] 551 | } 552 | else { 553 | voidptr(0) 554 | } 555 | } 556 | if !isnil(tex) { 557 | vsdl2.render_copy(g.renderer, tex, voidptr(0), &rect) 558 | } 559 | } 560 | } 561 | status := match g.status { 562 | .win { 'You win! Press Return..' } 563 | .pause { '*PAUSE* Press Space..' } 564 | else { '' } 565 | } 566 | ts := g.snap.state.time_s % 60 567 | tm := (g.snap.state.time_s / 60) % 60 568 | th := g.snap.state.time_s / 3600 569 | g.draw_text(0, g.height - text_size * text_ratio - 4, '${g.level+1:02d}| moves: ${g.snap.state.moves:04d} pushes: ${g.snap.state.pushes:04d} time:$th:${tm:02}:${ts:02} $status', 570 | text_color) 571 | C.SDL_RenderPresent(g.renderer) 572 | g.must_draw = false 573 | } 574 | } 575 | 576 | fn (mut g Game) handle_events() { 577 | ev := vsdl2.Event{} 578 | mut cont := true 579 | for cont && 0 < vsdl2.poll_event(&ev) { 580 | match int(ev.@type) { 581 | C.SDL_QUIT { 582 | g.quit = true 583 | cont = false 584 | break 585 | } 586 | C.SDL_KEYDOWN { 587 | key := ev.key.keysym.sym 588 | match key { 589 | C.SDLK_ESCAPE { 590 | g.quit = true 591 | cont = false 592 | break 593 | } 594 | C.SDLK_d { 595 | g.debug = !g.debug 596 | g.debug_dump() 597 | continue 598 | } 599 | else {} 600 | } 601 | } 602 | else {} 603 | } 604 | cont = match g.status { 605 | .win { g.handle_event_win(ev) } 606 | .play { g.handle_event_play(ev) } 607 | .pause { g.handle_event_pause(ev) } 608 | } 609 | } 610 | } 611 | 612 | fn (mut g Game) handle_event_play(ev vsdl2.Event) bool { 613 | mut cont := true 614 | match int(ev.@type) { 615 | C.SDL_KEYDOWN { 616 | key := ev.key.keysym.sym 617 | match key { 618 | C.SDLK_SPACE { 619 | g.status = .pause 620 | g.must_draw = true 621 | cont = false 622 | } 623 | C.SDLK_r { 624 | g.set_level(g.level) 625 | cont = false 626 | } 627 | C.SDLK_w { 628 | g.status = .win 629 | g.must_draw = true 630 | cont = false 631 | } 632 | C.SDLK_u { 633 | g.pop_undo() 634 | } 635 | C.SDLK_s { 636 | g.save_snapshot() 637 | } 638 | C.SDLK_l { 639 | g.load_snapshot() 640 | } 641 | C.SDLK_UP { 642 | g.try_move(0, -1) 643 | } 644 | C.SDLK_DOWN { 645 | g.try_move(0, 1) 646 | } 647 | C.SDLK_LEFT { 648 | g.try_move(-1, 0) 649 | } 650 | C.SDLK_RIGHT { 651 | g.try_move(1, 0) 652 | } 653 | else {} 654 | } 655 | } 656 | else {} 657 | } 658 | return cont 659 | } 660 | 661 | fn (mut g Game) handle_event_pause(ev vsdl2.Event) bool { 662 | mut cont := true 663 | match int(ev.@type) { 664 | C.SDL_KEYDOWN { 665 | key := ev.key.keysym.sym 666 | match key { 667 | C.SDLK_SPACE { 668 | g.status = .play 669 | g.must_draw = true 670 | cont = false 671 | } 672 | else {} 673 | } 674 | } 675 | else {} 676 | } 677 | return cont 678 | } 679 | 680 | fn (mut g Game) handle_event_win(ev vsdl2.Event) bool { 681 | mut cont := true 682 | match int(ev.@type) { 683 | C.SDL_KEYDOWN { 684 | key := ev.key.keysym.sym 685 | match key { 686 | C.SDLK_RETURN { 687 | if g.set_level(g.level + 1) { 688 | } else { 689 | println('Game over.') 690 | g.quit = true 691 | cont = false 692 | } 693 | } 694 | C.SDLK_u { 695 | g.pop_undo() 696 | g.status = .play 697 | g.must_draw = true 698 | cont = false 699 | } 700 | C.SDLK_r { 701 | g.set_level(g.level) 702 | cont = false 703 | } 704 | else {} 705 | } 706 | } 707 | else {} 708 | } 709 | return cont 710 | } 711 | 712 | fn (g Game) sleep() { 713 | vsdl2.delay(1000 / 60) 714 | } 715 | 716 | fn main() { 717 | mut game := new_game('クレートさん V') 718 | for !game.quit { 719 | game.handle_events() 720 | game.draw_map() 721 | game.sleep() 722 | } 723 | game.delete() 724 | } 725 | -------------------------------------------------------------------------------- /cratesan/res/images/crate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/cratesan/res/images/crate.png -------------------------------------------------------------------------------- /cratesan/res/images/cratesan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/cratesan/res/images/cratesan.png -------------------------------------------------------------------------------- /cratesan/res/images/empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/cratesan/res/images/empty.png -------------------------------------------------------------------------------- /cratesan/res/images/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/cratesan/res/images/player.png -------------------------------------------------------------------------------- /cratesan/res/images/splayer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/cratesan/res/images/splayer.png -------------------------------------------------------------------------------- /cratesan/res/images/store.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/cratesan/res/images/store.png -------------------------------------------------------------------------------- /cratesan/res/images/stored.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/cratesan/res/images/stored.png -------------------------------------------------------------------------------- /cratesan/res/images/wall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/cratesan/res/images/wall.png -------------------------------------------------------------------------------- /fonts/RobotoMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/fonts/RobotoMono-Regular.ttf -------------------------------------------------------------------------------- /game/C/Makefile: -------------------------------------------------------------------------------- 1 | TARGET:=game 2 | 3 | CFLAGS+=`sdl2-config --cflags` 4 | LDLIBS+=`sdl2-config --libs` 5 | 6 | CFLAGS+=-Wall -Werror 7 | 8 | all: game 9 | 10 | check: game 11 | ./game 12 | 13 | clean: 14 | $(RM) $(TARGET) 15 | -------------------------------------------------------------------------------- /game/C/game.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | typedef struct state { 9 | int quit; 10 | int w; 11 | int h; 12 | int bpp; 13 | int scale; 14 | int score; 15 | int fps; 16 | uint64_t tick; 17 | uint64_t last_tick; 18 | struct timespec last_ts; 19 | 20 | SDL_Surface *screen; 21 | SDL_Window *sdlWindow; 22 | SDL_Renderer *sdlRenderer; 23 | SDL_Texture *sdlTexture; 24 | Uint32 white; 25 | Uint32 black; 26 | } state_t; 27 | 28 | typedef struct input { 29 | int quit; 30 | } input_t; 31 | 32 | void die() { 33 | exit(1); 34 | } 35 | 36 | void init_state(state_t *s) { 37 | memset(s, 0, sizeof(state_t)); 38 | s->scale = 4; 39 | s->w = 200; 40 | s->h = 400; 41 | s->bpp = 32; 42 | if (SDL_Init(SDL_INIT_VIDEO) < 0) { 43 | die(); 44 | } 45 | SDL_CreateWindowAndRenderer(s->w, s->h, 0, &s->sdlWindow, &s->sdlRenderer); 46 | s->screen = SDL_CreateRGBSurface(0, s->w, s->h, s->bpp, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); 47 | s->sdlTexture = SDL_CreateTexture(s->sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, s->w, s->h); 48 | s->white = SDL_MapRGB(s->screen->format, 255, 255, 255); 49 | s->black = SDL_MapRGB(s->screen->format, 0, 0, 0); 50 | s->score = 42; 51 | clock_gettime(CLOCK_REALTIME, &s->last_ts); 52 | } 53 | 54 | void draw_clear(state_t *s, Uint32 col) { 55 | SDL_Rect rect; 56 | rect.x = 0; 57 | rect.y = 0; 58 | rect.w = s->w; 59 | rect.h = s->h; 60 | SDL_FillRect(s->screen, &rect, col); 61 | } 62 | 63 | void draw_score(state_t *s, Uint32 col, int score) { 64 | SDL_Rect rect; 65 | rect.x = 0; 66 | rect.y = 0; 67 | rect.w = s->scale; 68 | rect.h = s->scale; 69 | char sscore[1024]; 70 | int ndigits = sprintf(sscore, "%d", score); 71 | // 4x5 font 72 | const int fw = 4; 73 | const int fh = 5; 74 | int stride = (fw + 7) / 8 * fh; // bytes per font element 75 | char font[] = { 76 | /*0-9*/ 77 | 0x2,0x5,0x5,0x2,0x0, 78 | 0x2,0x6,0x2,0x7,0x0, 79 | 0x6,0x1,0x2,0x7,0x0, 80 | 0x7,0x3,0x1,0x6,0x0, 81 | 0x4,0x6,0x7,0x2,0x0, 82 | 0x7,0x4,0x1,0x6,0x0, 83 | 0x3,0x6,0x5,0x2,0x0, 84 | 0x7,0x1,0x2,0x4,0x0, 85 | 0x5,0x2,0x5,0x2,0x0, 86 | 0x2,0x5,0x3,0x6,0x0, 87 | }; 88 | for (int n = 0; n < ndigits; n++) { 89 | int digit = sscore[n] - '0'; 90 | for (int j = 0; j < fh; j++) { 91 | rect.y = s->scale * j; 92 | for (int i = 0; i < fw; i++) { 93 | rect.x = s->scale * (n * fw + i); 94 | if (font[digit * stride + j] & (1 << (fw - i - 1))) { 95 | SDL_FillRect(s->screen, &rect, col); 96 | } 97 | } 98 | } 99 | } 100 | } 101 | 102 | void draw_update(state_t *s) { 103 | SDL_UpdateTexture(s->sdlTexture, 0, s->screen->pixels, s->screen->pitch); 104 | SDL_RenderClear(s->sdlRenderer); 105 | SDL_RenderCopy(s->sdlRenderer, s->sdlTexture, 0, 0); 106 | SDL_RenderPresent(s->sdlRenderer); 107 | } 108 | 109 | void get_user_input(input_t *ui) { 110 | memset(ui, 0, sizeof(input_t)); 111 | SDL_Event ev; 112 | while (SDL_PollEvent(&ev)) { 113 | if (ev.type == SDL_QUIT) { 114 | ui->quit = 1; 115 | break; 116 | } 117 | if (ev.type == SDL_KEYDOWN) { 118 | if (ev.key.keysym.sym == SDLK_ESCAPE) { 119 | ui->quit = 1; 120 | break; 121 | } 122 | } 123 | } 124 | } 125 | 126 | void process_one_frame(state_t *s, input_t *user_input) { 127 | if (user_input->quit) { 128 | s->quit = 1; 129 | return; 130 | } 131 | struct timespec ts; 132 | clock_gettime(CLOCK_REALTIME, &ts); 133 | if (ts.tv_sec > s->last_ts.tv_sec) { 134 | s->fps = (s->tick - s->last_tick) / (ts.tv_sec - s->last_ts.tv_sec); 135 | s->last_tick = s->tick; 136 | s->last_ts = ts; 137 | // HACK 138 | s->score = s->fps; 139 | } 140 | s->tick++; 141 | } 142 | 143 | void draw_everything_on_screen(state_t *s) { 144 | draw_clear(s, s->black); 145 | draw_score(s, s->white, s->score); 146 | draw_update(s); 147 | } 148 | 149 | void wait_until_frame_time_elapsed() { 150 | SDL_Delay(16); 151 | } 152 | 153 | int main() { 154 | state_t state; 155 | init_state(&state); 156 | while (!state.quit) { 157 | input_t user_input; 158 | get_user_input(&user_input); 159 | process_one_frame(&state, &user_input); 160 | draw_everything_on_screen(&state); 161 | wait_until_frame_time_elapsed(); 162 | } 163 | return 0; 164 | } 165 | -------------------------------------------------------------------------------- /game/Rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "game" 3 | version = "0.1.0" 4 | authors = ["Nicolas Sauzede "] 5 | [dependencies] 6 | sdl2 = "0.33" 7 | -------------------------------------------------------------------------------- /game/Rust/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate sdl2; 2 | 3 | use sdl2::event::Event; 4 | use sdl2::keyboard::Keycode; 5 | use sdl2::pixels::Color; 6 | use sdl2::rect::Rect; 7 | use std::time::Duration; 8 | 9 | struct State { 10 | w: u32, 11 | h: u32, 12 | scale: u32, 13 | score: u32, 14 | fps: u32, 15 | sdl_context: sdl2::Sdl, 16 | canvas: sdl2::render::Canvas, 17 | quit: bool, 18 | tick: u64, 19 | last_tick: u64, 20 | last_time: std::time::SystemTime, 21 | } 22 | 23 | struct UserInput { 24 | quit: bool, 25 | } 26 | 27 | fn init_state() -> Result { 28 | let w = 200; 29 | let h = 400; 30 | let sdl_context = sdl2::init()?; 31 | let video_subsystem = sdl_context.video()?; 32 | let window = video_subsystem.window("game", w, h) 33 | .position_centered() 34 | .opengl() 35 | .build() 36 | .map_err(|e| e.to_string())?; 37 | let canvas = window.into_canvas().build().map_err(|e| e.to_string())?; 38 | 39 | Ok(State { 40 | w: w, 41 | h: h, 42 | scale: 4, 43 | score: 42, 44 | fps: 0, 45 | sdl_context: sdl_context, 46 | canvas: canvas, 47 | quit: false, 48 | tick: 0, 49 | last_tick: 0, 50 | last_time: std::time::SystemTime::now(), 51 | }) 52 | } 53 | 54 | fn draw_clear(s: &mut State) -> Result<(), String> { 55 | s.canvas.set_draw_color(Color::RGB(0, 0, 0)); 56 | s.canvas.clear(); 57 | s.canvas.fill_rect(Rect::new(0, 0, s.w, s.h))?; 58 | Ok(()) 59 | } 60 | 61 | fn draw_score(s: &mut State) -> Result<(), String> { 62 | s.canvas.set_draw_color(Color::RGB(255, 255, 255)); 63 | let mut rect = Rect::new(0,0,s.scale,s.scale); 64 | let score = s.score; 65 | let sscore = format!("{}", score); 66 | let ndigits = sscore.len(); 67 | // 4x5 font 68 | let fw = 4; 69 | let fh = 5; 70 | let stride = (fw + 7) / 8 * fh; // bytes per font element 71 | let font = [ 72 | /*0-9*/ 73 | 0x2,0x5,0x5,0x2,0x0, 74 | 0x2,0x6,0x2,0x7,0x0, 75 | 0x6,0x1,0x2,0x7,0x0, 76 | 0x7,0x3,0x1,0x6,0x0, 77 | 0x4,0x6,0x7,0x2,0x0, 78 | 0x7,0x4,0x1,0x6,0x0, 79 | 0x3,0x6,0x5,0x2,0x0, 80 | 0x7,0x1,0x2,0x4,0x0, 81 | 0x5,0x2,0x5,0x2,0x0, 82 | 0x2,0x5,0x3,0x6,0x0, 83 | ]; 84 | for n in 0..ndigits { 85 | let digit = sscore.chars().nth(n).unwrap() as i32 - '0' as i32; 86 | for j in 0..fh { 87 | rect.y = s.scale as i32 * j; 88 | for i in 0..fw { 89 | rect.x = s.scale as i32 * (n as i32 * fw + i); 90 | if 0 != (font[digit as usize * stride as usize + j as usize] & (1 << (fw - i - 1))) { 91 | s.canvas.fill_rect(rect)?; 92 | } 93 | } 94 | } 95 | } 96 | Ok(()) 97 | } 98 | 99 | fn draw_update(s: &mut State) -> Result<(), String> { 100 | s.canvas.present(); 101 | Ok(()) 102 | } 103 | 104 | fn get_user_input(s: &State) -> Result { 105 | let mut ui = UserInput { 106 | quit: false, 107 | }; 108 | let mut event_pump = s.sdl_context.event_pump()?; 109 | for event in event_pump.poll_iter() { 110 | match event { 111 | Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => { 112 | ui.quit = true; 113 | break 114 | }, 115 | _ => {} 116 | } 117 | } 118 | Ok(ui) 119 | } 120 | 121 | fn process_one_frame(s: &mut State, ui: &UserInput) { 122 | if ui.quit { 123 | s.quit = true; 124 | } 125 | let now = std::time::SystemTime::now(); 126 | let dur_s = now.duration_since(s.last_time).unwrap().as_secs(); 127 | if dur_s >= 1 { 128 | s.fps = ((s.tick - s.last_tick) / (dur_s)) as u32; 129 | s.last_tick = s.tick; 130 | s.last_time = now; 131 | // HACK 132 | s.score = s.fps; 133 | } 134 | s.tick += 1; 135 | } 136 | 137 | fn draw_everything_on_screen(s: &mut State) -> Result<(), String> { 138 | draw_clear(s)?; 139 | draw_score(s)?; 140 | draw_update(s)?; 141 | Ok(()) 142 | } 143 | 144 | fn wait_until_frame_time_elapsed(_s: &State) { 145 | ::std::thread::sleep(Duration::new(0, 16_666_666u32)); 146 | } 147 | 148 | fn main() -> Result<(), String> { 149 | let mut state = init_state()?; 150 | while !state.quit { 151 | let user_input = get_user_input(&state)?; 152 | process_one_frame(&mut state, &user_input); 153 | draw_everything_on_screen(&mut state)?; 154 | wait_until_frame_time_elapsed(&state); 155 | } 156 | Ok(()) 157 | } 158 | -------------------------------------------------------------------------------- /glfnt.cpp: -------------------------------------------------------------------------------- 1 | // Std. Includes 2 | #include 3 | #include 4 | #include 5 | // GLEW 6 | #define GLEW_STATIC 7 | #include 8 | // GLFW 9 | #include 10 | // GLM 11 | #include 12 | #include 13 | #include 14 | // FreeType 15 | #include 16 | #include FT_FREETYPE_H 17 | // GL includes 18 | #include "Shader.h" 19 | 20 | // Properties 21 | const GLuint WIDTH = 800, HEIGHT = 600; 22 | 23 | /// Holds all state information relevant to a character as loaded using FreeType 24 | struct Character { 25 | GLuint TextureID; // ID handle of the glyph texture 26 | glm::ivec2 Size; // Size of glyph 27 | glm::ivec2 Bearing; // Offset from baseline to left/top of glyph 28 | GLuint Advance; // Horizontal offset to advance to next glyph 29 | }; 30 | 31 | std::map Characters; 32 | GLuint VAO, VBO; 33 | 34 | void RenderText(Shader &shader, std::string text, GLfloat x, GLfloat y, GLfloat scale, glm::vec3 color); 35 | 36 | // The MAIN function, from here we start our application and run the Game loop 37 | int main() 38 | { 39 | // Init GLFW 40 | glfwInit(); 41 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 42 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 43 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 44 | glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); 45 | 46 | GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr); // Windowed 47 | glfwMakeContextCurrent(window); 48 | 49 | // Initialize GLEW to setup the OpenGL Function pointers 50 | glewExperimental = GL_TRUE; 51 | glewInit(); 52 | 53 | // Define the viewport dimensions 54 | glViewport(0, 0, WIDTH, HEIGHT); 55 | 56 | // Set OpenGL options 57 | glEnable(GL_CULL_FACE); 58 | glEnable(GL_BLEND); 59 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 60 | 61 | // Compile and setup the shader 62 | Shader shader("shaders/text.vs", "shaders/text.frag"); 63 | glm::mat4 projection = glm::ortho(0.0f, static_cast(WIDTH), 0.0f, static_cast(HEIGHT)); 64 | shader.use(); 65 | shader.setMat4("projection", projection); 66 | 67 | // FreeType 68 | FT_Library ft; 69 | // All functions return a value different than 0 whenever an error occurred 70 | if (FT_Init_FreeType(&ft)) 71 | std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl; 72 | 73 | // Load font as face 74 | FT_Face face; 75 | if (FT_New_Face(ft, "fonts/RobotoMono-Regular.ttf", 0, &face)) { 76 | std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl; 77 | exit(1); 78 | } 79 | 80 | // Set size to load glyphs as 81 | FT_Set_Pixel_Sizes(face, 0, 48); 82 | 83 | // Disable byte-alignment restriction 84 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 85 | 86 | // Load first 128 characters of ASCII set 87 | for (GLubyte c = 0; c < 128; c++) 88 | { 89 | // Load character glyph 90 | if (FT_Load_Char(face, c, FT_LOAD_RENDER)) 91 | { 92 | std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl; 93 | continue; 94 | } 95 | // Generate texture 96 | GLuint texture; 97 | glGenTextures(1, &texture); 98 | glBindTexture(GL_TEXTURE_2D, texture); 99 | glTexImage2D( 100 | GL_TEXTURE_2D, 101 | 0, 102 | GL_RED, 103 | face->glyph->bitmap.width, 104 | face->glyph->bitmap.rows, 105 | 0, 106 | GL_RED, 107 | GL_UNSIGNED_BYTE, 108 | face->glyph->bitmap.buffer 109 | ); 110 | // Set texture options 111 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 112 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 113 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 114 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 115 | // Now store character for later use 116 | Character character = { 117 | texture, 118 | glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows), 119 | glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top), 120 | (GLuint)face->glyph->advance.x 121 | }; 122 | Characters.insert(std::pair(c, character)); 123 | } 124 | glBindTexture(GL_TEXTURE_2D, 0); 125 | // Destroy FreeType once we're finished 126 | FT_Done_Face(face); 127 | FT_Done_FreeType(ft); 128 | 129 | // Configure VAO/VBO for texture quads 130 | glGenVertexArrays(1, &VAO); 131 | glGenBuffers(1, &VBO); 132 | glBindVertexArray(VAO); 133 | glBindBuffer(GL_ARRAY_BUFFER, VBO); 134 | glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, NULL, GL_DYNAMIC_DRAW); 135 | glEnableVertexAttribArray(0); 136 | glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0); 137 | glBindBuffer(GL_ARRAY_BUFFER, 0); 138 | glBindVertexArray(0); 139 | 140 | // Game loop 141 | while (!glfwWindowShouldClose(window)) 142 | { 143 | // Check and call events 144 | glfwPollEvents(); 145 | 146 | // Clear the colorbuffer 147 | glClearColor(0.2f, 0.3f, 0.3f, 1.0f); 148 | glClear(GL_COLOR_BUFFER_BIT); 149 | 150 | RenderText(shader, "This is sample text", 25.0f, 25.0f, 1.0f, glm::vec3(0.5, 0.8f, 0.2f)); 151 | RenderText(shader, "(C) LearnOpenGL.com", 520.0f, 570.0f, 0.5f, glm::vec3(0.3, 0.7f, 0.9f)); 152 | 153 | // Swap the buffers 154 | glfwSwapBuffers(window); 155 | } 156 | 157 | glfwTerminate(); 158 | return 0; 159 | } 160 | 161 | void RenderText(Shader &shader, std::string text, GLfloat x, GLfloat y, GLfloat scale, glm::vec3 color) 162 | { 163 | // Activate corresponding render state 164 | shader.use(); 165 | shader.setVec3("fontColor", color.x, color.y, color.z); 166 | glActiveTexture(GL_TEXTURE0); 167 | glBindVertexArray(VAO); 168 | 169 | // Iterate through all characters 170 | std::string::const_iterator c; 171 | for (c = text.begin(); c != text.end(); c++) 172 | { 173 | Character ch = Characters[*c]; 174 | 175 | GLfloat xpos = x + ch.Bearing.x * scale; 176 | GLfloat ypos = y - (ch.Size.y - ch.Bearing.y) * scale; 177 | 178 | GLfloat w = ch.Size.x * scale; 179 | GLfloat h = ch.Size.y * scale; 180 | // Update VBO for each character 181 | GLfloat vertices[6][4] = { 182 | { xpos, ypos + h, 0.0, 0.0 }, 183 | { xpos, ypos, 0.0, 1.0 }, 184 | { xpos + w, ypos, 1.0, 1.0 }, 185 | 186 | { xpos, ypos + h, 0.0, 0.0 }, 187 | { xpos + w, ypos, 1.0, 1.0 }, 188 | { xpos + w, ypos + h, 1.0, 0.0 } 189 | }; 190 | // Render glyph texture over quad 191 | glBindTexture(GL_TEXTURE_2D, ch.TextureID); 192 | // Update content of VBO memory 193 | glBindBuffer(GL_ARRAY_BUFFER, VBO); 194 | glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); // Be sure to use glBufferSubData and not glBufferData 195 | 196 | glBindBuffer(GL_ARRAY_BUFFER, 0); 197 | // Render quad 198 | glDrawArrays(GL_TRIANGLES, 0, 6); 199 | // Now advance cursors for next glyph (note that advance is number of 1/64 pixels) 200 | x += (ch.Advance >> 6) * scale; // Bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels)) 201 | } 202 | glBindVertexArray(0); 203 | glBindTexture(GL_TEXTURE_2D, 0); 204 | } 205 | -------------------------------------------------------------------------------- /images/gb_head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/images/gb_head.png -------------------------------------------------------------------------------- /images/v-logo_30_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/images/v-logo_30_30.png -------------------------------------------------------------------------------- /main_c.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define SDL_DISABLE_IMMINTRIN_H 5 | #include 6 | #ifdef SDL2 7 | #include 8 | #include 9 | #endif 10 | 11 | typedef struct AudioCtx_s { 12 | // dynamic 13 | Uint8 *audio_pos; // current pointer to the audio buffer to be played 14 | Uint32 audio_len; // remaining length of the sample we have to play 15 | // static at load 16 | SDL_AudioSpec wav_spec; // the specs of our piece of music 17 | Uint8 *wav_buffer; // buffer containing our audio file 18 | Uint32 wav_length; // length of our sample 19 | } AudioCtx; 20 | 21 | void my_audio_callback(void *userdata, Uint8 *stream, int _len) { 22 | Uint32 len = _len; 23 | AudioCtx *ctx = userdata; 24 | if (ctx->audio_len ==0) 25 | return; 26 | 27 | len = ( len > ctx->audio_len ? ctx->audio_len : len ); 28 | SDL_memset(stream, 0, len); 29 | //SDL_memcpy (stream, audio_pos, len); // 30 | SDL_MixAudio(stream, ctx->audio_pos, len, SDL_MIX_MAXVOLUME);// mix from on 31 | 32 | ctx->audio_pos += len; 33 | ctx->audio_len -= len; 34 | } 35 | 36 | int main(int argc, char *argv[]) { 37 | #ifdef SDL1 38 | #define SDLV 1 39 | #else 40 | #define SDLV 2 41 | #endif 42 | printf("hello SDL %d\n", SDLV); 43 | char *soundpath = "sounds/door2.wav"; 44 | int w = 200; 45 | int h = 400; 46 | int bpp = 32; 47 | SDL_Surface *screen = 0; 48 | #ifdef SDL1 49 | #else 50 | SDL_Window *sdlWindow = 0; 51 | SDL_Renderer *sdlRenderer = 0; 52 | SDL_Texture *sdlTexture = 0; 53 | TTF_Font *font = 0; 54 | #endif 55 | 56 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) return 1; 57 | #ifdef SDL1 58 | screen = SDL_SetVideoMode(w, h, bpp, 0); 59 | #else 60 | SDL_CreateWindowAndRenderer(w, h, 0, &sdlWindow, &sdlRenderer); 61 | screen = SDL_CreateRGBSurface(0, w, h, bpp,0x00FF0000,0x0000FF00,0x000000FF,0xFF000000); 62 | sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, w, h); 63 | #endif 64 | if (!screen) { 65 | printf("failed to init SDL screen\n"); 66 | exit(1); 67 | } 68 | atexit(SDL_Quit); 69 | #ifdef SDL2 70 | if (TTF_Init() == -1) { 71 | printf("failed to init TTF\n"); 72 | exit(1); 73 | } 74 | atexit(TTF_Quit); 75 | font = TTF_OpenFont("fonts/RobotoMono-Regular.ttf", 16); 76 | #endif 77 | 78 | AudioCtx actx; 79 | #ifdef SDL2 80 | SDL_zero(actx); 81 | #else 82 | memset(&actx, 0, sizeof(actx)); 83 | #endif 84 | if( SDL_LoadWAV(soundpath, &actx.wav_spec, &actx.wav_buffer, &actx.wav_length) == NULL ){ 85 | printf("couldn't load wav\n"); 86 | return 1; 87 | } 88 | // set the callback function 89 | actx.wav_spec.callback = my_audio_callback; 90 | actx.wav_spec.userdata = &actx; 91 | 92 | /* Open the audio device */ 93 | if ( SDL_OpenAudio(&actx.wav_spec, NULL) < 0 ){ 94 | fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError()); 95 | exit(-1); 96 | } 97 | 98 | #ifdef SDL2 99 | IMG_Init(IMG_INIT_PNG); 100 | SDL_Surface *img = IMG_Load("images/gb_head.png"); 101 | SDL_Texture *imgtex = SDL_CreateTextureFromSurface(sdlRenderer, img); 102 | printf("img=%p imgtex=%p\n", img, imgtex); 103 | #endif 104 | 105 | int quit = 0; 106 | int ballx = 0, bally = h / 2, balld = 10, balldir = 1; 107 | while (!quit) { 108 | SDL_Event event; 109 | while (SDL_PollEvent(&event)) { 110 | if (event.type == SDL_QUIT) { 111 | quit = 1; 112 | break; 113 | } 114 | if (event.type == SDL_KEYDOWN) { 115 | if (event.key.keysym.sym == SDLK_ESCAPE) { 116 | quit = 1; 117 | break; 118 | } 119 | } 120 | } 121 | if (quit) 122 | break; 123 | SDL_Rect rect; 124 | rect.x = 0; 125 | rect.y = 0; 126 | rect.w = w; 127 | rect.h = h; 128 | Uint32 col = SDL_MapRGB(screen->format, 255, 255, 255); 129 | SDL_FillRect(screen, &rect, col); 130 | 131 | rect.x = ballx; 132 | rect.y = bally; 133 | rect.w = balld; 134 | rect.h = balld; 135 | col = SDL_MapRGB(screen->format, 255, 0, 0); 136 | SDL_FillRect(screen, &rect, col); 137 | ballx += balldir; 138 | if (balldir == 1) { 139 | if (ballx >= w - balld) { 140 | balldir = -1; 141 | // trigger sound restart 142 | actx.audio_pos = actx.wav_buffer; // copy sound buffer 143 | actx.audio_len = actx.wav_length; // copy file length 144 | /* Start playing */ 145 | SDL_PauseAudio(0); 146 | } 147 | } else { 148 | if (ballx <= 0) { 149 | balldir = 1; 150 | // trigger sound restart 151 | actx.audio_pos = actx.wav_buffer; // copy sound buffer 152 | actx.audio_len = actx.wav_length; // copy file length 153 | /* Start playing */ 154 | SDL_PauseAudio(0); 155 | } 156 | } 157 | 158 | #ifdef SDL1 159 | SDL_UpdateRect(screen, 0, 0, 0, 0); 160 | #else 161 | SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch); 162 | SDL_RenderClear(sdlRenderer); 163 | SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); 164 | if (font) { 165 | SDL_Color color = { 0, 0, 0, 0 }; 166 | SDL_Surface * surface = TTF_RenderText_Solid(font,"Hello SDL_ttf", color); 167 | SDL_Texture * texture = SDL_CreateTextureFromSurface(sdlRenderer, surface); 168 | int texW = 0; 169 | int texH = 0; 170 | SDL_QueryTexture(texture, NULL, NULL, &texW, &texH); 171 | SDL_Rect dstrect = { 0, 0, texW, texH }; 172 | SDL_RenderCopy(sdlRenderer, texture, NULL, &dstrect); 173 | SDL_DestroyTexture(texture); 174 | SDL_FreeSurface(surface); 175 | } 176 | #ifdef SDL2 177 | rect.w = 32; 178 | rect.h = 32; 179 | rect.x = (w - rect.w) / 2; 180 | rect.y = (h - rect.h) / 2; 181 | SDL_RenderCopy(sdlRenderer, imgtex, NULL, &rect); 182 | // SDL_RenderCopy(sdlRenderer, imgtex, NULL, NULL); 183 | #endif 184 | 185 | SDL_RenderPresent(sdlRenderer); 186 | #endif 187 | SDL_Delay(10); 188 | } 189 | #ifdef SDL2 190 | if (font) { 191 | TTF_CloseFont(font); 192 | } 193 | #endif 194 | // shut everything audio down 195 | SDL_CloseAudio(); 196 | SDL_FreeWAV(actx.wav_buffer); 197 | printf("bye\n"); 198 | 199 | return 0; 200 | } 201 | -------------------------------------------------------------------------------- /main_cpp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "CSDL.h" 6 | 7 | int main( int argc, char *argv[]) { 8 | int help = 0; 9 | int arg = 1; 10 | while (arg < argc) { 11 | if (!strcmp( argv[arg], "--help")){ 12 | help = 1; 13 | } 14 | arg++; 15 | } 16 | if (help) { 17 | printf( "TODO: write help\n"); 18 | exit( 0); 19 | } 20 | #ifdef SDL1 21 | #define SDLV 1 22 | #else 23 | #define SDLV 2 24 | #endif 25 | std::cout << "hello SDL " << SDLV << std::endl; 26 | CSDL sdl; 27 | sdl.Init(); 28 | int quit = 0; 29 | while (!quit) { 30 | if (sdl.Poll()) { 31 | quit = 1; 32 | break; 33 | } 34 | sdl.Draw(); 35 | sdl.Delay( 500); 36 | } 37 | std::cout << "bye" << std::endl; 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /maingl_c.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #ifdef SDL2 6 | #include 7 | #endif 8 | //#define GL_GLEXT_PROTOTYPES // to get glGenBuffers(), .. 9 | #include 10 | #include 11 | 12 | typedef struct AudioCtx_s { 13 | // dynamic 14 | Uint8 *audio_pos; // current pointer to the audio buffer to be played 15 | Uint32 audio_len; // remaining length of the sample we have to play 16 | // static at load 17 | SDL_AudioSpec wav_spec; // the specs of our piece of music 18 | Uint8 *wav_buffer; // buffer containing our audio file 19 | Uint32 wav_length; // length of our sample 20 | } AudioCtx; 21 | 22 | void my_audio_callback(void *userdata, Uint8 *stream, int _len) { 23 | Uint32 len = _len; 24 | AudioCtx *ctx = userdata; 25 | if (ctx->audio_len ==0) 26 | return; 27 | 28 | len = ( len > ctx->audio_len ? ctx->audio_len : len ); 29 | SDL_memset(stream, 0, len); 30 | //SDL_memcpy (stream, audio_pos, len); // 31 | SDL_MixAudio(stream, ctx->audio_pos, len, SDL_MIX_MAXVOLUME);// mix from on 32 | 33 | ctx->audio_pos += len; 34 | ctx->audio_len -= len; 35 | } 36 | 37 | //#define USE2D 38 | void GlFillRect(SDL_Surface *screen, SDL_Rect *rect, SDL_Color *col) { 39 | int ww = screen->w; 40 | int hh = screen->h; 41 | GLfloat x = (GLfloat)2 * rect->x / (ww - 1) - 1; // 0->w-1 => 0->2 => -1->+1 42 | GLfloat y = (GLfloat)2 * ((hh - 1) - rect->y) / (hh - 1) - 1; // 0->h-1 => 1->0 => 2->0 => +1->-1 43 | GLfloat w = (GLfloat)2 * rect->w / ww; 44 | GLfloat h = (GLfloat)2 * rect->h / hh; 45 | GLfloat r = (GLfloat)col->r / 255; 46 | GLfloat g = (GLfloat)col->g / 255; 47 | GLfloat b = (GLfloat)col->b / 255; 48 | 49 | glColor3f(r, g, b); 50 | // glBegin(GL_QUADS); 51 | glVertex2f(x, y); 52 | glVertex2f(x + w, y); 53 | glVertex2f(x + w, y - h); 54 | glVertex2f(x, y - h); 55 | // glEnd(); 56 | } 57 | 58 | void GlTestTexture(SDL_Surface *screen) { 59 | int ww = screen->w; 60 | int hh = screen->h; 61 | SDL_Rect _rect, *rect = &_rect; 62 | SDL_Color _col, *col = &_col; 63 | _rect.x = 10; 64 | _rect.y = 10; 65 | _rect.w = 50; 66 | _rect.h = 80; 67 | _col.r = 0; 68 | _col.g = 0; 69 | _col.b = 200; 70 | GLfloat x = (GLfloat)2 * rect->x / (ww - 1) - 1; // 0->w-1 => 0->2 => -1->+1 71 | GLfloat y = (GLfloat)2 * ((hh - 1) - rect->y) / (hh - 1) - 1; // 0->h-1 => 1->0 => 2->0 => +1->-1 72 | GLfloat w = (GLfloat)2 * rect->w / ww; 73 | GLfloat h = (GLfloat)2 * rect->h / hh; 74 | GLfloat r = (GLfloat)col->r / 255; 75 | GLfloat g = (GLfloat)col->g / 255; 76 | GLfloat b = (GLfloat)col->b / 255; 77 | 78 | glColor3f(r, g, b); 79 | #if 0 80 | glBegin(GL_QUADS); 81 | glVertex2f(x, y); 82 | glVertex2f(x + w, y); 83 | glVertex2f(x + w, y - h); 84 | glVertex2f(x, y - h); 85 | glEnd(); 86 | #else 87 | glBegin(GL_TRIANGLES); 88 | glVertex3f(-0.5, -0.5, 0); 89 | glVertex3f(0.5, -0.5, 0); 90 | glVertex3f(0, 0.5, 0); 91 | glEnd(); 92 | #endif 93 | } 94 | 95 | int main(int argc, char *argv[]) { 96 | #ifdef WIN32 97 | setbuf(stdout, 0); 98 | #endif 99 | 100 | #ifdef SDL1 101 | #define SDLV 1 102 | #else 103 | #define SDLV 2 104 | #endif 105 | printf("hello SDL %d\n", SDLV); 106 | char *soundpath = "sounds/door2.wav"; 107 | int w = 400; 108 | int h = 300; 109 | int bpp = 32; 110 | SDL_Surface *screen = 0; 111 | #ifdef SDL1 112 | #else 113 | SDL_Window *sdlWindow = 0; 114 | SDL_Renderer *sdlRenderer = 0; 115 | #ifdef USE2D 116 | SDL_Texture *sdlTexture = 0; 117 | #endif 118 | TTF_Font *font = 0; 119 | #endif 120 | 121 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) return 1; 122 | #ifdef SDL1 123 | screen = SDL_SetVideoMode(w, h, bpp, 0); 124 | #else 125 | SDL_CreateWindowAndRenderer(w, h, 0, &sdlWindow, &sdlRenderer); 126 | screen = SDL_CreateRGBSurface(0, w, h, bpp,0x00FF0000,0x0000FF00,0x000000FF,0xFF000000); 127 | #ifdef USE2D 128 | sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, w, h); 129 | #endif 130 | // OpenGL 131 | // Loosely followed the great SDL2+OpenGL2.1 tutorial here : 132 | // http://lazyfoo.net/tutorials/OpenGL/01_hello_opengl/index2.php 133 | SDL_GLContext glContext = SDL_GL_CreateContext(sdlWindow); 134 | if (glContext == NULL) { 135 | printf("Couldn't create OpenGL context !\n"); 136 | } else { 137 | printf("Created OpenGL context.\n"); 138 | } 139 | if (SDL_GL_SetSwapInterval(1) < 0) { 140 | printf("Couldn't use VSync !\n"); 141 | } else { 142 | printf("Using VSync.\n"); 143 | } 144 | glMatrixMode(GL_PROJECTION); 145 | glLoadIdentity(); 146 | glMatrixMode(GL_MODELVIEW); 147 | glLoadIdentity(); 148 | glClearColor(0.f, 0.f, 0.f, 1.f); 149 | #endif 150 | if (!screen) { 151 | printf("failed to init SDL screen\n"); 152 | exit(1); 153 | } 154 | atexit(SDL_Quit); 155 | #ifdef SDL2 156 | if (TTF_Init() == -1) { 157 | printf("failed to init TTF\n"); 158 | exit(1); 159 | } 160 | atexit(TTF_Quit); 161 | font = TTF_OpenFont("fonts/RobotoMono-Regular.ttf", 16); 162 | #endif 163 | 164 | AudioCtx actx; 165 | #ifdef SDL2 166 | SDL_zero(actx); 167 | #else 168 | memset(&actx, 0, sizeof(actx)); 169 | #endif 170 | if( SDL_LoadWAV(soundpath, &actx.wav_spec, &actx.wav_buffer, &actx.wav_length) == NULL ){ 171 | printf("couldn't load wav\n"); 172 | return 1; 173 | } 174 | // set the callback function 175 | actx.wav_spec.callback = my_audio_callback; 176 | actx.wav_spec.userdata = &actx; 177 | 178 | /* Open the audio device */ 179 | if ( SDL_OpenAudio(&actx.wav_spec, NULL) < 0 ){ 180 | fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError()); 181 | exit(-1); 182 | } 183 | 184 | int quit = 0; 185 | int ballx = 0, bally = h / 2, balld = 10, balldir = 1, balldelt = balld / 2; 186 | int nangle = 0; 187 | int wireframe = 0; 188 | #if 0 189 | GLuint vbo; 190 | glGenBuffers(1, &vbo); 191 | #endif 192 | while (!quit) { 193 | SDL_Event event; 194 | while (SDL_PollEvent(&event)) { 195 | if (event.type == SDL_QUIT) { 196 | quit = 1; 197 | break; 198 | } 199 | if (event.type == SDL_KEYDOWN) { 200 | if (event.key.keysym.sym == SDLK_ESCAPE) { 201 | quit = 1; 202 | break; 203 | } 204 | if (event.key.keysym.sym == SDLK_w) { 205 | wireframe = 1 - wireframe; 206 | break; 207 | } 208 | } 209 | } 210 | if (quit) 211 | break; 212 | ballx += balldir * balldelt; 213 | if (balldir == 1) { 214 | if (ballx >= w - balld) { 215 | balldir = -1; 216 | // trigger sound restart 217 | actx.audio_pos = actx.wav_buffer; // copy sound buffer 218 | actx.audio_len = actx.wav_length; // copy file length 219 | /* Start playing */ 220 | SDL_PauseAudio(0); 221 | } 222 | } else { 223 | if (ballx <= 0) { 224 | balldir = 1; 225 | // trigger sound restart 226 | actx.audio_pos = actx.wav_buffer; // copy sound buffer 227 | actx.audio_len = actx.wav_length; // copy file length 228 | /* Start playing */ 229 | SDL_PauseAudio(0); 230 | } 231 | } 232 | 233 | #ifdef SDL1 234 | SDL_UpdateRect(screen, 0, 0, 0, 0); 235 | #else 236 | #ifdef USE2D 237 | #if 1 238 | SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch); 239 | SDL_RenderClear(sdlRenderer); 240 | SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); 241 | #endif 242 | #if 1 243 | SDL_Rect rect = {0, 0, w, h}; 244 | Uint32 col = SDL_MapRGB(screen->format, 0, 0, 0); 245 | SDL_FillRect(screen, &rect, col); 246 | #if 0 247 | rect.x = 0;rect.y = 0;rect.w = w / 2;rect.h = h / 2; 248 | col = SDL_MapRGB(screen->format, 0, 255, 0); 249 | SDL_FillRect(screen, &rect, col); 250 | 251 | rect.x = w / 2;rect.y = h / 2;rect.w = w / 2;rect.h = h / 2; 252 | col = SDL_MapRGB(screen->format, 0, 0, 255); 253 | SDL_FillRect(screen, &rect, col); 254 | #endif 255 | rect.x = ballx;rect.y = bally;rect.w = balld;rect.h = balld; 256 | col = SDL_MapRGB(screen->format, 255, 0, 0); 257 | SDL_FillRect(screen, &rect, col); 258 | #endif 259 | #if 1 260 | if (font) { 261 | SDL_Color color = { 255, 255, 255 }; 262 | SDL_Surface * surface = TTF_RenderText_Solid(font,"Hello SDL OpenGL", color); 263 | SDL_Texture * texture = SDL_CreateTextureFromSurface(sdlRenderer, surface); 264 | int texW = 0; 265 | int texH = 0; 266 | SDL_QueryTexture(texture, NULL, NULL, &texW, &texH); 267 | SDL_Rect dstrect = { 0, 0, texW, texH }; 268 | SDL_RenderCopy(sdlRenderer, texture, NULL, &dstrect); 269 | SDL_DestroyTexture(texture); 270 | SDL_FreeSurface(surface); 271 | } 272 | #endif 273 | SDL_RenderPresent(sdlRenderer); 274 | #else 275 | glClear(GL_COLOR_BUFFER_BIT); 276 | glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL); 277 | #if 1 278 | #define DELT 2 279 | float angle = nangle * DELT; 280 | nangle++; 281 | glMatrixMode(GL_MODELVIEW); 282 | glLoadIdentity(); 283 | glRotatef(angle,1,1,1); 284 | glBegin(GL_QUADS); 285 | glColor3f(0.f, 0.f, 0.2f); 286 | glVertex2f(-0.5f, -0.5f); 287 | glColor3f(1.f, 0.f, 0.2f); 288 | glVertex2f(0.5f, -0.5f); 289 | glColor3f(1.f, 1.f, 0.2f); 290 | glVertex2f(0.5f, 0.5f); 291 | glColor3f(0.f, 1.f, 0.2f); 292 | glVertex2f(-0.5f, 0.5f); 293 | glEnd(); 294 | #endif 295 | #if 1 296 | glMatrixMode(GL_MODELVIEW); 297 | glLoadIdentity(); 298 | glBegin(GL_QUADS); 299 | SDL_Rect rect; 300 | SDL_Color col; 301 | #if 0 302 | rect.x = 0;rect.y = 0; rect.w = w / 2; rect.h = h / 2; 303 | col.r = 0; col.g = 255;col.b = 0; 304 | GlFillRect(screen, &rect, &col); 305 | 306 | rect.x = w / 2;rect.y = h / 2;rect.w = w / 2;rect.h = h / 2; 307 | col.r = 0;col.g = 0;col.b = 255; 308 | GlFillRect(screen, &rect, &col); 309 | #endif 310 | rect.x = ballx;rect.y = bally;rect.w = balld;rect.h = balld; 311 | col.r = 255;col.g = 0;col.b = 0; 312 | GlFillRect(screen, &rect, &col); 313 | 314 | glEnd(); 315 | 316 | GlTestTexture(screen); 317 | #endif 318 | SDL_GL_SwapWindow(sdlWindow); 319 | #endif 320 | #endif 321 | SDL_Delay(10); 322 | } 323 | #ifdef SDL2 324 | if (font) { 325 | TTF_CloseFont(font); 326 | } 327 | #endif 328 | // shut everything audio down 329 | SDL_CloseAudio(); 330 | SDL_FreeWAV(actx.wav_buffer); 331 | printf("bye\n"); 332 | 333 | return 0; 334 | } 335 | -------------------------------------------------------------------------------- /maingl_v.v: -------------------------------------------------------------------------------- 1 | // Copyright(C) 2019 Nicolas Sauzede. All rights reserved. 2 | // Use of this source code is governed by an MIT license 3 | // that can be found in the LICENSE_v.txt file. 4 | module main 5 | 6 | import nsauzede.vsdl2 7 | import vsdl2gl 8 | [inline] fn sdl_fill_rect(s &vsdl2.Surface,r &vsdl2.Rect,c &vsdl2.Color) {vsdl2gl.fill_rect(s,r,c)} 9 | 10 | type atexit_func_t fn () 11 | //fn C.atexit(atexit_func_t) 12 | 13 | const ( 14 | Colors = [ 15 | vsdl2.Color{byte(255), byte(255), byte(255), byte(0)}, 16 | vsdl2.Color{byte(255), byte(0), byte(0), byte(0)} 17 | ] 18 | ) 19 | 20 | struct AudioContext { 21 | mut: 22 | // audio_pos *byte 23 | audio_pos voidptr 24 | audio_len u32 25 | wav_spec SdlAudioSpec 26 | wav_buffer &byte 27 | wav_length u32 28 | wav2_buffer &byte 29 | wav2_length u32 30 | } 31 | 32 | fn acb(userdata voidptr, stream &byte, _len int) { 33 | mut ctx := &AudioContext(userdata) 34 | // println('acb!!! wav_buffer=${ctx.wav_buffer} audio_len=${ctx.audio_len}') 35 | if ctx.audio_len == u32(0) { 36 | C.memset(stream, 0, _len) 37 | return 38 | } 39 | mut len := u32(_len) 40 | if len > ctx.audio_len { len = ctx.audio_len } 41 | C.memcpy(stream, ctx.audio_pos, len) 42 | // ctx.audio_pos = voidptr(u64(ctx.audio_pos) + u64(len)) 43 | ctx.audio_pos += len 44 | ctx.audio_len -= len 45 | } 46 | fn main() { 47 | println('hello SDL2 OpenGL V !!') 48 | w := 400 49 | h := 300 50 | bpp := 32 51 | sdl_window := *voidptr(0) 52 | sdl_renderer := *voidptr(0) 53 | C.SDL_Init(C.SDL_INIT_VIDEO | C.SDL_INIT_AUDIO) 54 | C.atexit(C.SDL_Quit) 55 | C.SDL_CreateWindowAndRenderer(w, h, 0, &sdl_window, &sdl_renderer) 56 | // println('renderer=$sdl_renderer') 57 | screen := C.SDL_CreateRGBSurface(0, w, h, bpp, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000) 58 | // sdl_texture := C.SDL_CreateTexture(sdl_renderer, C.SDL_PIXELFORMAT_ARGB8888, C.SDL_TEXTUREACCESS_STREAMING, w, h) 59 | glinit := true 60 | if glinit { 61 | // OpenGL 62 | // Loosely followed the great SDL2+OpenGL2.1 tutorial here : 63 | // http://lazyfoo.net/tutorials/OpenGL/01_hello_opengl/index2.php 64 | gl_context := C.SDL_GL_CreateContext(sdl_window) 65 | if isnil(gl_context) { 66 | println('Couldn\'t create OpenGL context !') 67 | } else { 68 | println('Created OpenGL context.') 69 | } 70 | C.SDL_GL_SetSwapInterval(1) 71 | C.glMatrixMode(C.GL_PROJECTION) 72 | C.glLoadIdentity() 73 | C.glMatrixMode(C.GL_MODELVIEW) 74 | C.glLoadIdentity() 75 | C.glClearColor(0., 0., 0., 1.) 76 | } 77 | mut actx := AudioContext{} 78 | C.SDL_zero(actx) 79 | C.SDL_LoadWAV('sounds/door2.wav', &actx.wav_spec, &actx.wav_buffer, &actx.wav_length) 80 | C.SDL_LoadWAV('sounds/single.wav', &actx.wav_spec, &actx.wav2_buffer, &actx.wav2_length) 81 | actx.wav_spec.callback = acb 82 | actx.wav_spec.userdata = &actx 83 | if C.SDL_OpenAudio(&actx.wav_spec, 0) < 0 { 84 | println('couldn\'t open audio') 85 | return 86 | } 87 | mut quit := false 88 | mut ballx := 0 89 | bally := h / 2 90 | balld := 10 91 | ballm := balld / 2 92 | mut balldir := ballm 93 | mut nangle := 0 94 | mut show_3d := true 95 | for !quit { 96 | ev := SdlEvent{} 97 | for 0 < C.SDL_PollEvent(&ev) { 98 | switch int(ev._type) { 99 | case C.SDL_QUIT: 100 | quit = true 101 | break 102 | case C.SDL_KEYDOWN: 103 | switch int(ev.key.keysym.sym) { 104 | case C.SDLK_ESCAPE: 105 | quit = true 106 | break 107 | case C.SDLK_SPACE: 108 | actx.audio_pos = actx.wav2_buffer 109 | actx.audio_len = actx.wav2_length 110 | C.SDL_PauseAudio(0) 111 | case C.SDLK_3: 112 | show_3d = !show_3d 113 | } 114 | } 115 | } 116 | if quit { 117 | break 118 | } 119 | ballx += balldir 120 | if balldir == ballm { 121 | if ballx >= w - balld { 122 | balldir = -ballm 123 | actx.audio_pos = actx.wav_buffer 124 | actx.audio_len = actx.wav_length 125 | C.SDL_PauseAudio(0) 126 | } 127 | } else { 128 | if ballx <= 0 { 129 | balldir = ballm 130 | actx.audio_pos = actx.wav_buffer 131 | actx.audio_len = actx.wav_length 132 | C.SDL_PauseAudio(0) 133 | } 134 | } 135 | 136 | mut rect := SdlRect{} 137 | mut col := vsdl2.SdlColor{} 138 | // 2D part 139 | rect = SdlRect {0, 0, w, h} 140 | col = vsdl2.SdlColor{byte(0), byte(0), byte(0), byte(0)} 141 | sdl_fill_rect(screen, &rect, &col) 142 | if show_3d { 143 | // 3D part 144 | // following line is useless if we wipe the screen in 2D above (sdl_fill_rect) 145 | // C.glClear(C.GL_COLOR_BUFFER_BIT) 146 | 147 | C.glMatrixMode(C.GL_MODELVIEW) 148 | C.glLoadIdentity() 149 | angle := f32(nangle) * 2 150 | C.glRotatef(angle,f32(1),f32(1),f32(1)) 151 | C.glBegin(C.GL_QUADS) 152 | C.glColor3f(0., 0., 0.2) 153 | C.glVertex2f(-0.5, -0.5) 154 | C.glColor3f(1., 0., 0.2) 155 | C.glVertex2f(0.5, -0.5) 156 | C.glColor3f(1., 1., 0.2) 157 | C.glVertex2f(0.5, 0.5) 158 | C.glColor3f(0., 1., 0.2) 159 | C.glVertex2f(-0.5, 0.5) 160 | C.glEnd() 161 | nangle++ 162 | } 163 | 164 | // 2D part 165 | rect = SdlRect {ballx, bally, balld, balld} 166 | col = vsdl2.SdlColor{byte(255), byte(0), byte(0), byte(0)} 167 | sdl_fill_rect(screen, &rect, &col) 168 | 169 | // 3D part 170 | C.SDL_GL_SwapWindow(sdl_window) 171 | 172 | C.SDL_Delay(10) 173 | } 174 | C.SDL_CloseAudio() 175 | if voidptr(actx.wav_buffer) != voidptr(0) { 176 | C.SDL_FreeWAV(actx.wav_buffer) 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /mainglsl_c.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #ifdef SDL2 6 | #include 7 | #endif 8 | //#define GL_GLEXT_PROTOTYPES // to get glGenBuffers(), .. 9 | #include 10 | #include 11 | 12 | typedef struct AudioCtx_s { 13 | // dynamic 14 | Uint8 *audio_pos; // current pointer to the audio buffer to be played 15 | Uint32 audio_len; // remaining length of the sample we have to play 16 | // static at load 17 | SDL_AudioSpec wav_spec; // the specs of our piece of music 18 | Uint8 *wav_buffer; // buffer containing our audio file 19 | Uint32 wav_length; // length of our sample 20 | } AudioCtx; 21 | 22 | void my_audio_callback(void *userdata, Uint8 *stream, int len) { 23 | AudioCtx *ctx = userdata; 24 | if (ctx->audio_len ==0) 25 | return; 26 | 27 | len = ( len > ctx->audio_len ? ctx->audio_len : len ); 28 | SDL_memset(stream, 0, len); 29 | //SDL_memcpy (stream, audio_pos, len); // 30 | SDL_MixAudio(stream, ctx->audio_pos, len, SDL_MIX_MAXVOLUME);// mix from on 31 | 32 | ctx->audio_pos += len; 33 | ctx->audio_len -= len; 34 | } 35 | 36 | //#define USE2D 37 | void GlFillRect(SDL_Surface *screen, SDL_Rect *rect, SDL_Color *col) { 38 | int ww = screen->w; 39 | int hh = screen->h; 40 | GLfloat x = (GLfloat)2 * rect->x / (ww - 1) - 1; // 0->w-1 => 0->2 => -1->+1 41 | GLfloat y = (GLfloat)2 * ((hh - 1) - rect->y) / (hh - 1) - 1; // 0->h-1 => 1->0 => 2->0 => +1->-1 42 | GLfloat w = (GLfloat)2 * rect->w / ww; 43 | GLfloat h = (GLfloat)2 * rect->h / hh; 44 | GLfloat r = (GLfloat)col->r / 255; 45 | GLfloat g = (GLfloat)col->g / 255; 46 | GLfloat b = (GLfloat)col->b / 255; 47 | 48 | glColor3f(r, g, b); 49 | // glBegin(GL_QUADS); 50 | glVertex2f(x, y); 51 | glVertex2f(x + w, y); 52 | glVertex2f(x + w, y - h); 53 | glVertex2f(x, y - h); 54 | // glEnd(); 55 | } 56 | 57 | void GlTestTexture(SDL_Surface *screen) { 58 | int ww = screen->w; 59 | int hh = screen->h; 60 | SDL_Rect _rect, *rect = &_rect; 61 | SDL_Color _col, *col = &_col; 62 | _rect.x = 10; 63 | _rect.y = 10; 64 | _rect.w = 50; 65 | _rect.h = 80; 66 | _col.r = 0; 67 | _col.g = 0; 68 | _col.b = 200; 69 | GLfloat x = (GLfloat)2 * rect->x / (ww - 1) - 1; // 0->w-1 => 0->2 => -1->+1 70 | GLfloat y = (GLfloat)2 * ((hh - 1) - rect->y) / (hh - 1) - 1; // 0->h-1 => 1->0 => 2->0 => +1->-1 71 | GLfloat w = (GLfloat)2 * rect->w / ww; 72 | GLfloat h = (GLfloat)2 * rect->h / hh; 73 | GLfloat r = (GLfloat)col->r / 255; 74 | GLfloat g = (GLfloat)col->g / 255; 75 | GLfloat b = (GLfloat)col->b / 255; 76 | 77 | glColor3f(r, g, b); 78 | #if 0 79 | glBegin(GL_QUADS); 80 | glVertex2f(x, y); 81 | glVertex2f(x + w, y); 82 | glVertex2f(x + w, y - h); 83 | glVertex2f(x, y - h); 84 | glEnd(); 85 | #else 86 | glBegin(GL_TRIANGLES); 87 | glVertex3f(-0.5, -0.5, 0); 88 | glVertex3f(0.5, -0.5, 0); 89 | glVertex3f(0, 0.5, 0); 90 | glEnd(); 91 | #endif 92 | } 93 | 94 | int main(int argc, char *argv[]) { 95 | #ifdef SDL1 96 | #define SDLV 1 97 | #else 98 | #define SDLV 2 99 | #endif 100 | printf("hello SDL %d\n", SDLV); 101 | char *soundpath = "sounds/door2.wav"; 102 | int w = 400; 103 | int h = 300; 104 | int bpp = 32; 105 | SDL_Surface *screen = 0; 106 | #ifdef SDL1 107 | #else 108 | SDL_Window *sdlWindow = 0; 109 | SDL_Renderer *sdlRenderer = 0; 110 | SDL_Texture *sdlTexture = 0; 111 | TTF_Font *font = 0; 112 | #endif 113 | 114 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) return 1; 115 | #ifdef SDL1 116 | screen = SDL_SetVideoMode(w, h, bpp, 0); 117 | #else 118 | SDL_CreateWindowAndRenderer(w, h, 0, &sdlWindow, &sdlRenderer); 119 | screen = SDL_CreateRGBSurface(0, w, h, bpp,0x00FF0000,0x0000FF00,0x000000FF,0xFF000000); 120 | sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, w, h); 121 | // OpenGL 122 | // Loosely followed the great SDL2+OpenGL2.1 tutorial here : 123 | // http://lazyfoo.net/tutorials/OpenGL/01_hello_opengl/index2.php 124 | SDL_GLContext glContext = SDL_GL_CreateContext(sdlWindow); 125 | if (glContext == NULL) { 126 | printf("Couldn't create OpenGL context !\n"); 127 | } else { 128 | printf("Created OpenGL context.\n"); 129 | } 130 | if (SDL_GL_SetSwapInterval(1) < 0) { 131 | printf("Couldn't use VSync !\n"); 132 | } else { 133 | printf("Using VSync.\n"); 134 | } 135 | glMatrixMode(GL_PROJECTION); 136 | glLoadIdentity(); 137 | glMatrixMode(GL_MODELVIEW); 138 | glLoadIdentity(); 139 | glClearColor(0.f, 0.f, 0.f, 1.f); 140 | 141 | const char *vertexShaderSource = "#version 330 core\n" 142 | "layout (location = 0) in vec3 aPos;\n" 143 | // "out vec3 ourColor;\n" 144 | "void main()\n" 145 | "{\n" 146 | " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" 147 | // " ourColor = vec3(0.0f, 0.0f. 1.0f);\n" 148 | "}\n"; 149 | const char *fragmentShaderSource = "#version 330 core\n" 150 | "out vec4 FragColor;\n" 151 | // "in vec3 ourColor;\n" 152 | "void main()\n" 153 | "{\n" 154 | // " FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" 155 | " FragColor = vec4(0.0f, 1.0f, 0.0f, 1.0f);\n" 156 | // " FragColor = vec4(ourColor, 1.0f);\n" 157 | "}\n"; 158 | unsigned int VBO; 159 | glGenBuffers(1, &VBO); 160 | unsigned int vertexShader; 161 | vertexShader = glCreateShader(GL_VERTEX_SHADER); 162 | glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); 163 | glCompileShader(vertexShader); 164 | unsigned int fragmentShader; 165 | fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 166 | glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); 167 | glCompileShader(fragmentShader); 168 | unsigned int shaderProgram; 169 | shaderProgram = glCreateProgram(); 170 | glAttachShader(shaderProgram, vertexShader); 171 | glAttachShader(shaderProgram, fragmentShader); 172 | glLinkProgram(shaderProgram); 173 | glDeleteShader(vertexShader); 174 | glDeleteShader(fragmentShader); 175 | 176 | #if 0 177 | int width = 100, height = 100, nrChannels = 3; 178 | unsigned dsize = width * height * nrChannels; 179 | unsigned char *data = malloc(dsize); 180 | // stbi_load("container.jpg", &width, &height, &nrChannels, 0); 181 | unsigned int texture; 182 | glGenTextures(1, &texture); 183 | glBindTexture(GL_TEXTURE_2D, texture); 184 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 185 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 186 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 187 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 188 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); 189 | glGenerateMipmap(GL_TEXTURE_2D); 190 | free(data); 191 | #endif 192 | 193 | #endif 194 | if (!screen) { 195 | printf("failed to init SDL screen\n"); 196 | exit(1); 197 | } 198 | atexit(SDL_Quit); 199 | #ifdef SDL2 200 | if (TTF_Init() == -1) { 201 | printf("failed to init TTF\n"); 202 | exit(1); 203 | } 204 | atexit(TTF_Quit); 205 | font = TTF_OpenFont("fonts/RobotoMono-Regular.ttf", 16); 206 | #endif 207 | 208 | AudioCtx actx; 209 | #ifdef SDL2 210 | SDL_zero(actx); 211 | #else 212 | memset(&actx, 0, sizeof(actx)); 213 | #endif 214 | if( SDL_LoadWAV(soundpath, &actx.wav_spec, &actx.wav_buffer, &actx.wav_length) == NULL ){ 215 | printf("couldn't load wav\n"); 216 | return 1; 217 | } 218 | // set the callback function 219 | actx.wav_spec.callback = my_audio_callback; 220 | actx.wav_spec.userdata = &actx; 221 | 222 | /* Open the audio device */ 223 | if ( SDL_OpenAudio(&actx.wav_spec, NULL) < 0 ){ 224 | fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError()); 225 | exit(-1); 226 | } 227 | 228 | int quit = 0; 229 | int ballx = 0, bally = h / 2, balld = 10, balldir = 1, balldelt = balld / 2; 230 | int nangle = 0; 231 | int wireframe = 0; 232 | #if 0 233 | GLuint vbo; 234 | glGenBuffers(1, &vbo); 235 | #endif 236 | while (!quit) { 237 | SDL_Event event; 238 | while (SDL_PollEvent(&event)) { 239 | if (event.type == SDL_QUIT) { 240 | quit = 1; 241 | break; 242 | } 243 | if (event.type == SDL_KEYDOWN) { 244 | if (event.key.keysym.sym == SDLK_ESCAPE) { 245 | quit = 1; 246 | break; 247 | } 248 | if (event.key.keysym.sym == SDLK_w) { 249 | wireframe = 1 - wireframe; 250 | break; 251 | } 252 | } 253 | } 254 | if (quit) 255 | break; 256 | ballx += balldir * balldelt; 257 | if (balldir == 1) { 258 | if (ballx >= w - balld) { 259 | balldir = -1; 260 | // trigger sound restart 261 | actx.audio_pos = actx.wav_buffer; // copy sound buffer 262 | actx.audio_len = actx.wav_length; // copy file length 263 | /* Start playing */ 264 | SDL_PauseAudio(0); 265 | } 266 | } else { 267 | if (ballx <= 0) { 268 | balldir = 1; 269 | // trigger sound restart 270 | actx.audio_pos = actx.wav_buffer; // copy sound buffer 271 | actx.audio_len = actx.wav_length; // copy file length 272 | /* Start playing */ 273 | SDL_PauseAudio(0); 274 | } 275 | } 276 | 277 | #ifdef SDL1 278 | SDL_UpdateRect(screen, 0, 0, 0, 0); 279 | #else 280 | #ifdef USE2D 281 | #if 1 282 | SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch); 283 | SDL_RenderClear(sdlRenderer); 284 | SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); 285 | #endif 286 | #if 1 287 | SDL_Rect rect = {0, 0, w, h}; 288 | Uint32 col = SDL_MapRGB(screen->format, 0, 0, 0); 289 | SDL_FillRect(screen, &rect, col); 290 | #if 0 291 | rect.x = 0;rect.y = 0;rect.w = w / 2;rect.h = h / 2; 292 | col = SDL_MapRGB(screen->format, 0, 255, 0); 293 | SDL_FillRect(screen, &rect, col); 294 | 295 | rect.x = w / 2;rect.y = h / 2;rect.w = w / 2;rect.h = h / 2; 296 | col = SDL_MapRGB(screen->format, 0, 0, 255); 297 | SDL_FillRect(screen, &rect, col); 298 | #endif 299 | rect.x = ballx;rect.y = bally;rect.w = balld;rect.h = balld; 300 | col = SDL_MapRGB(screen->format, 255, 0, 0); 301 | SDL_FillRect(screen, &rect, col); 302 | #endif 303 | #if 1 304 | if (font) { 305 | SDL_Color color = { 255, 255, 255 }; 306 | SDL_Surface * surface = TTF_RenderText_Solid(font,"Hello SDL OpenGL", color); 307 | SDL_Texture * texture = SDL_CreateTextureFromSurface(sdlRenderer, surface); 308 | int texW = 0; 309 | int texH = 0; 310 | SDL_QueryTexture(texture, NULL, NULL, &texW, &texH); 311 | SDL_Rect dstrect = { 0, 0, texW, texH }; 312 | SDL_RenderCopy(sdlRenderer, texture, NULL, &dstrect); 313 | SDL_DestroyTexture(texture); 314 | SDL_FreeSurface(surface); 315 | } 316 | #endif 317 | SDL_RenderPresent(sdlRenderer); 318 | #else 319 | glClear(GL_COLOR_BUFFER_BIT); 320 | glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL); 321 | #if 1 322 | #define DELT 2 323 | float angle = nangle * DELT; 324 | nangle++; 325 | glMatrixMode(GL_MODELVIEW); 326 | glLoadIdentity(); 327 | glRotatef(angle,1,1,1); 328 | glBegin(GL_QUADS); 329 | glColor3f(0.f, 0.f, 0.2f); 330 | glVertex2f(-0.5f, -0.5f); 331 | glColor3f(1.f, 0.f, 0.2f); 332 | glVertex2f(0.5f, -0.5f); 333 | glColor3f(1.f, 1.f, 0.2f); 334 | glVertex2f(0.5f, 0.5f); 335 | glColor3f(0.f, 1.f, 0.2f); 336 | glVertex2f(-0.5f, 0.5f); 337 | glEnd(); 338 | #endif 339 | #if 1 340 | glMatrixMode(GL_MODELVIEW); 341 | glLoadIdentity(); 342 | glBegin(GL_QUADS); 343 | SDL_Rect rect; 344 | SDL_Color col; 345 | #if 0 346 | rect.x = 0;rect.y = 0; rect.w = w / 2; rect.h = h / 2; 347 | col.r = 0; col.g = 255;col.b = 0; 348 | GlFillRect(screen, &rect, &col); 349 | 350 | rect.x = w / 2;rect.y = h / 2;rect.w = w / 2;rect.h = h / 2; 351 | col.r = 0;col.g = 0;col.b = 255; 352 | GlFillRect(screen, &rect, &col); 353 | #endif 354 | rect.x = ballx;rect.y = bally;rect.w = balld;rect.h = balld; 355 | col.r = 255;col.g = 0;col.b = 0; 356 | GlFillRect(screen, &rect, &col); 357 | 358 | glEnd(); 359 | 360 | float vertices[] = { 361 | -0.5f, -0.5f, 0.0f, 362 | 0.5f, -0.5f, 0.0f, 363 | 0.0f, 0.5f, 0.0f 364 | }; 365 | glBindBuffer(GL_ARRAY_BUFFER, VBO); 366 | glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 367 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); 368 | glEnableVertexAttribArray(0); 369 | glUseProgram(shaderProgram); 370 | glDrawArrays(GL_TRIANGLES, 0, 3); 371 | 372 | // GlTestTexture(screen); 373 | #endif 374 | SDL_GL_SwapWindow(sdlWindow); 375 | #endif 376 | #endif 377 | SDL_Delay(10); 378 | } 379 | #ifdef SDL2 380 | if (font) { 381 | TTF_CloseFont(font); 382 | } 383 | #endif 384 | // shut everything audio down 385 | SDL_CloseAudio(); 386 | SDL_FreeWAV(actx.wav_buffer); 387 | printf("bye\n"); 388 | 389 | return 0; 390 | } 391 | -------------------------------------------------------------------------------- /mainmix_c.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #ifdef SDL2 6 | #endif 7 | #include 8 | #include 9 | 10 | typedef struct AudioCtx_s { 11 | Mix_Chunk *wave; 12 | } AudioCtx; 13 | 14 | #if 1 15 | #define BUFFER 1024 16 | Sint16 stream[2][BUFFER*2*2]; 17 | int len=BUFFER*2*2, done=0, need_refresh=0, bits=0, which=0, 18 | sample_size=0, position=0, rate=0; 19 | #endif 20 | 21 | void print_init_flags(int flags) 22 | { 23 | #define PFLAG(a) if(flags&MIX_INIT_##a) printf(#a " ") 24 | PFLAG(FLAC); 25 | PFLAG(MOD); 26 | PFLAG(MP3); 27 | PFLAG(OGG); 28 | if(!flags) 29 | printf("None"); 30 | printf("\n"); 31 | } 32 | 33 | int main(int argc, char *argv[]) { 34 | #ifdef WIN32 35 | setbuf(stdout, 0); // this to avoid stdout buffering on windows/mingw 36 | #endif 37 | 38 | #ifdef SDL1 39 | #define SDLV 1 40 | #else 41 | #define SDLV 2 42 | #endif 43 | printf("hello SDL %d\n", SDLV); 44 | char *soundpath = "sounds/door2.wav"; 45 | int w = 200; 46 | int h = 400; 47 | int bpp = 32; 48 | SDL_Surface *screen = 0; 49 | #ifdef SDL1 50 | #else 51 | SDL_Window *sdlWindow = 0; 52 | SDL_Renderer *sdlRenderer = 0; 53 | SDL_Texture *sdlTexture = 0; 54 | TTF_Font *font = 0; 55 | #endif 56 | 57 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) return 1; 58 | atexit(SDL_Quit); 59 | #ifdef SDL1 60 | screen = SDL_SetVideoMode(w, h, bpp, 0); 61 | #else 62 | SDL_CreateWindowAndRenderer(w, h, 0, &sdlWindow, &sdlRenderer); 63 | screen = SDL_CreateRGBSurface(0, w, h, bpp,0x00FF0000,0x0000FF00,0x000000FF,0xFF000000); 64 | sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, w, h); 65 | #endif 66 | if (!screen) { 67 | printf("failed to init SDL screen\n"); 68 | exit(1); 69 | } 70 | #ifdef SDL2 71 | if (TTF_Init() == -1) { 72 | printf("failed to init TTF\n"); 73 | exit(1); 74 | } 75 | atexit(TTF_Quit); 76 | font = TTF_OpenFont("fonts/RobotoMono-Regular.ttf", 16); 77 | #endif 78 | int audio_rate,audio_channels; 79 | Uint16 audio_format; 80 | Uint32 t; 81 | Mix_Music *music; 82 | int volume=SDL_MIX_MAXVOLUME; 83 | 84 | int initted=Mix_Init(0); 85 | #if 1 86 | printf("Before Mix_Init SDL_mixer supported: "); 87 | print_init_flags(initted); 88 | initted=Mix_Init(~0); 89 | printf("After Mix_Init SDL_mixer supported: "); 90 | print_init_flags(initted); 91 | Mix_Quit(); 92 | #endif 93 | if(Mix_OpenAudio(44100,MIX_DEFAULT_FORMAT,2,BUFFER)<0) { 94 | printf("error Mix_OpenAudio\n"); 95 | exit(1); 96 | } 97 | #if 1 98 | /* we play no samples, so deallocate the default 8 channels...*/ 99 | // Mix_AllocateChannels(0); 100 | { 101 | int i,n=Mix_GetNumChunkDecoders(); 102 | printf("There are %d available chunk(sample) decoders:\n", n); 103 | for(i=0; i1?"stereo":"mono", BUFFER ); 117 | // music=Mix_LoadMUS("sounds/SuperTwintrisThoseThree.mod"); 118 | #endif 119 | music=Mix_LoadMUS("sounds/TwintrisThosenine.mod"); 120 | #if 1 121 | if (music) { 122 | Mix_MusicType type=Mix_GetMusicType(music); 123 | printf("Music type: %s\n", 124 | type==MUS_NONE?"MUS_NONE": 125 | type==MUS_CMD?"MUS_CMD": 126 | type==MUS_WAV?"MUS_WAV": 127 | /*type==MUS_MOD_MODPLUG?"MUS_MOD_MODPLUG":*/ 128 | type==MUS_MOD?"MUS_MOD": 129 | type==MUS_MID?"MUS_MID": 130 | type==MUS_OGG?"MUS_OGG": 131 | type==MUS_MP3?"MUS_MP3": 132 | // type==MUS_MP3_MAD?"MUS_MP3_MAD": 133 | type==MUS_FLAC?"MUS_FLAC": 134 | "Unknown"); 135 | } 136 | #endif 137 | #if 1 138 | AudioCtx actx; 139 | #ifdef SDL2 140 | SDL_zero(actx); 141 | #else 142 | memset(&actx, 0, sizeof(actx)); 143 | #endif 144 | actx.wave = Mix_LoadWAV(soundpath); 145 | if (actx.wave == NULL ){ 146 | printf("couldn't load wav\n"); 147 | return 1; 148 | } 149 | #endif 150 | printf("%i joysticks were found.\n\n", SDL_NumJoysticks() ); 151 | printf("The names of the joysticks are:\n"); 152 | 153 | for( int i=0; i < SDL_NumJoysticks(); i++ ) 154 | { 155 | SDL_Joystick *joy = SDL_JoystickOpen(i); 156 | printf("Opened Joystick %d\n", i); 157 | #ifdef SDL1 158 | // char *name = SDL_JoystickName(i); 159 | // printf(" %s\n", name ? name : "(noname)"); 160 | printf("Name: %s\n", SDL_JoystickName(i)); 161 | #else 162 | printf("Name: %s\n", SDL_JoystickNameForIndex(i)); 163 | #endif 164 | printf("Number of Axes: %d\n", SDL_JoystickNumAxes(joy)); 165 | printf("Number of Buttons: %d\n", SDL_JoystickNumButtons(joy)); 166 | printf("Number of Balls: %d\n", SDL_JoystickNumBalls(joy)); 167 | } 168 | SDL_JoystickEventState(SDL_ENABLE); 169 | // Mix_SetPostMix(postmix,argv[1]); 170 | #if 1 171 | if(Mix_PlayMusic(music, 1)!=-1) { 172 | Mix_VolumeMusic(volume); 173 | } 174 | #endif 175 | int quit = 0; 176 | int ballx = 0, bally = h / 2, balld = 10, balldir = 1; 177 | int pause = 0; 178 | while (!quit) { 179 | SDL_Event event; 180 | while (SDL_PollEvent(&event)) { 181 | if (event.type == SDL_QUIT) { 182 | quit = 1; 183 | break; 184 | } 185 | #ifdef SDL2 186 | if (event.type == SDL_JOYDEVICEADDED) { 187 | printf("JOYDEVADDED\n"); 188 | continue; 189 | } 190 | #endif 191 | if (event.type == SDL_JOYHATMOTION) { 192 | printf("hat\n"); 193 | continue; 194 | } 195 | if (event.type == SDL_JOYAXISMOTION) { 196 | // printf("axis\n"); 197 | continue; 198 | } 199 | if (event.type == SDL_JOYBUTTONDOWN) { 200 | printf("EVENT JOYSTICK : button=%d\n", event.jbutton.button); 201 | if (event.jbutton.button == 0) { 202 | // trigger sound restart 203 | Mix_PlayChannel(0, actx.wave, 0); 204 | } 205 | continue; 206 | } 207 | if (event.type == SDL_KEYDOWN) { 208 | if (event.key.keysym.sym == SDLK_ESCAPE) { 209 | quit = 1; 210 | break; 211 | } 212 | if (event.key.keysym.sym == SDLK_RETURN) { 213 | if (!pause) { 214 | // trigger sound restart 215 | Mix_PlayChannel(0, actx.wave, 0); 216 | } 217 | continue; 218 | } 219 | if (event.key.keysym.sym == SDLK_SPACE) { 220 | pause = 1 - pause; 221 | if (pause) { 222 | Mix_PauseMusic(); 223 | } else { 224 | Mix_ResumeMusic(); 225 | } 226 | continue; 227 | } 228 | } 229 | } 230 | if (quit) 231 | break; 232 | SDL_Rect rect; 233 | rect.x = 0; 234 | rect.y = 0; 235 | rect.w = w; 236 | rect.h = h; 237 | Uint32 col = SDL_MapRGB(screen->format, 255, 255, 255); 238 | SDL_FillRect(screen, &rect, col); 239 | 240 | rect.x = ballx; 241 | rect.y = bally; 242 | rect.w = balld; 243 | rect.h = balld; 244 | col = SDL_MapRGB(screen->format, 255, 0, 0); 245 | SDL_FillRect(screen, &rect, col); 246 | if (!pause) { 247 | ballx += balldir; 248 | if (balldir == 1) { 249 | if (ballx >= w - balld) { 250 | balldir = -1; 251 | // trigger sound restart 252 | Mix_PlayChannel(0, actx.wave, 0); 253 | } 254 | } else { 255 | if (ballx <= 0) { 256 | balldir = 1; 257 | // trigger sound restart 258 | Mix_PlayChannel(0, actx.wave, 0); 259 | } 260 | } 261 | } 262 | #ifdef SDL1 263 | SDL_UpdateRect(screen, 0, 0, 0, 0); 264 | #else 265 | SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch); 266 | SDL_RenderClear(sdlRenderer); 267 | SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); 268 | if (font) { 269 | SDL_Color color = { 0, 0, 0, 0 }; 270 | SDL_Surface * surface = TTF_RenderText_Solid(font,"Hello SDL ttf/mixer", color); 271 | SDL_Texture * texture = SDL_CreateTextureFromSurface(sdlRenderer, surface); 272 | int texW = 0; 273 | int texH = 0; 274 | SDL_QueryTexture(texture, NULL, NULL, &texW, &texH); 275 | SDL_Rect dstrect = { 0, 0, texW, texH }; 276 | SDL_RenderCopy(sdlRenderer, texture, NULL, &dstrect); 277 | SDL_DestroyTexture(texture); 278 | SDL_FreeSurface(surface); 279 | } 280 | SDL_RenderPresent(sdlRenderer); 281 | #endif 282 | SDL_Delay(10); 283 | } 284 | #ifdef SDL2 285 | if (font) { 286 | TTF_CloseFont(font); 287 | } 288 | #endif 289 | if (actx.wave) { 290 | Mix_FreeChunk(actx.wave); 291 | } 292 | if (music) 293 | Mix_FreeMusic(music); 294 | Mix_CloseAudio(); 295 | printf("bye\n"); 296 | 297 | return 0; 298 | } 299 | -------------------------------------------------------------------------------- /sdl.mak: -------------------------------------------------------------------------------- 1 | 2 | ifndef SDLCONFIG 3 | 4 | SDL1CONFIG=sdl-config 5 | ifneq ($(shell a=`which $(SDL1CONFIG) 2>&1`;echo $$?),0) 6 | SDL1CONFIG= 7 | endif 8 | 9 | SDL2CONFIG=sdl2-config 10 | ifneq ($(shell a=`which $(SDL2CONFIG) 2>&1`;echo $$?),0) 11 | SDL2CONFIG= 12 | endif 13 | 14 | ifdef SDL2CONFIG 15 | SDLCONFIG=$(SDL2CONFIG) 16 | else 17 | ifdef SDL1CONFIG 18 | SDLCONFIG=$(SDL1CONFIG) 19 | endif 20 | endif 21 | 22 | ifndef SDLCONFIG 23 | SDLCONFIG=NO_SDL_INSTALLED 24 | SDL_CHECK: 25 | @echo "No SDL installed.\nTry : $$ sudo apt-get install libsdl2-dev";false 26 | else 27 | SDL_CHECK: 28 | @echo "Using detected SDLCONFIG=$(SDLCONFIG)" 29 | endif 30 | 31 | else 32 | 33 | SDL_CHECK: 34 | @echo "Using forced SDLCONFIG=$(SDLCONFIG)" 35 | 36 | endif 37 | 38 | ifdef SDLCONFIG 39 | SDL_FLAGS+=`$(SDLCONFIG) --cflags` 40 | endif 41 | 42 | OP_SYS=$(shell uname -o) 43 | ifeq ($(OP_SYS),Msys) 44 | WINDOWS=1 45 | endif 46 | 47 | ifdef WINDOWS 48 | #SDL_STATIC=1 49 | endif 50 | 51 | SDL_VER=$(shell $(SDLCONFIG) --version | cut -f 1 -d ".") 52 | ifeq ($(SDL_VER),1) 53 | USE_SDL1=1 54 | else 55 | USE_SDL1= 56 | endif 57 | 58 | ifdef SDL_STATIC 59 | SDL_LIBS+=`$(SDLCONFIG) --static-libs` -static 60 | else 61 | SDL_LIBS+=`$(SDLCONFIG) --libs` 62 | endif 63 | ifdef WINDOWS 64 | # this one to get text console output 65 | SDL_LIBS+=-mno-windows 66 | endif 67 | -------------------------------------------------------------------------------- /sdl1/Makefile: -------------------------------------------------------------------------------- 1 | TARGET:= 2 | TARGET+=main121 3 | TARGET+=main122 4 | TARGET+=main12 5 | 6 | all: $(TARGET) 7 | 8 | SDL1_CFLAGS:=`sdl-config --cflags` 9 | SDL1_LIBS:=`sdl-config --libs` 10 | SDL2_CFLAGS:=`sdl2-config --cflags` 11 | SDL2_LIBS:=`sdl2-config --libs` 12 | 13 | main121: CFLAGS+=$(SDL1_CFLAGS) -DSDL1 14 | main121: LDLIBS+=$(SDL1_LIBS) 15 | 16 | main122: CFLAGS+=$(SDL2_CFLAGS) -DSDL2 17 | main122: LDLIBS+=$(SDL2_LIBS) 18 | 19 | main12: CFLAGS+=-I. $(SDL2_CFLAGS) -DSDL1 20 | main12: LDLIBS+=$(SDL2_LIBS) 21 | 22 | main121: main12.c 23 | $(CC) -o $@ $^ $(CFLAGS) $(LDLIBS) 24 | 25 | main122: main12.c 26 | $(CC) -o $@ $^ $(CFLAGS) $(LDLIBS) 27 | 28 | main12: main12.c 29 | $(CC) -o $@ $^ $(CFLAGS) $(LDLIBS) 30 | 31 | clean: 32 | $(RM) $(TARGET) 33 | -------------------------------------------------------------------------------- /sdl1/SDL.h: -------------------------------------------------------------------------------- 1 | #ifndef LOCAL_SDL_H 2 | #define LOCAL_SDL_H 3 | 4 | #include_next 5 | 6 | static SDL_Window *g_local_sdlWindow = 0; 7 | static SDL_Renderer *g_local_sdlRenderer = 0; 8 | static SDL_Texture *g_local_sdlTexture = 0; 9 | static inline SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags) { 10 | SDL_CreateWindowAndRenderer(width, height, 0, &g_local_sdlWindow, &g_local_sdlRenderer); 11 | SDL_Surface *screen = SDL_CreateRGBSurface(0, width, height, bpp, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); 12 | g_local_sdlTexture = SDL_CreateTexture(g_local_sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height); 13 | return screen; 14 | } 15 | 16 | static inline void SDL_UpdateRect(SDL_Surface *screen, Sint32 x, Sint32 y, Sint32 w, Sint32 h) { 17 | SDL_UpdateTexture(g_local_sdlTexture, NULL, screen->pixels, screen->pitch); 18 | SDL_RenderClear(g_local_sdlRenderer); 19 | SDL_RenderCopy(g_local_sdlRenderer, g_local_sdlTexture, NULL, NULL); 20 | SDL_RenderPresent(g_local_sdlRenderer); 21 | } 22 | 23 | #endif/*LOCAL_SDL_H*/ 24 | -------------------------------------------------------------------------------- /sdl1/main12.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define SDL_DISABLE_IMMINTRIN_H 5 | #include 6 | 7 | int main(int argc, char *argv[]) { 8 | #ifdef SDL1 9 | #define SDLV 1 10 | #else 11 | #define SDLV 2 12 | #endif 13 | printf("hello SDL %d\n", SDLV); 14 | int w = 200; 15 | int h = 400; 16 | int bpp = 32; 17 | SDL_Surface *screen = 0; 18 | #ifdef SDL1 19 | #else 20 | SDL_Window *sdlWindow = 0; 21 | SDL_Renderer *sdlRenderer = 0; 22 | SDL_Texture *sdlTexture = 0; 23 | #endif 24 | 25 | if (SDL_Init(SDL_INIT_VIDEO) < 0) return 1; 26 | #ifdef SDL1 27 | screen = SDL_SetVideoMode(w, h, bpp, 0); 28 | #else 29 | SDL_CreateWindowAndRenderer(w, h, 0, &sdlWindow, &sdlRenderer); 30 | screen = SDL_CreateRGBSurface(0, w, h, bpp,0x00FF0000,0x0000FF00,0x000000FF,0xFF000000); 31 | sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, w, h); 32 | #endif 33 | if (!screen) { 34 | printf("failed to init SDL screen\n"); 35 | exit(1); 36 | } 37 | atexit(SDL_Quit); 38 | int quit = 0; 39 | int ballx = 0, bally = h / 2, balld = 10, balldir = 1; 40 | while (!quit) { 41 | SDL_Event event; 42 | while (SDL_PollEvent(&event)) { 43 | if (event.type == SDL_QUIT) { 44 | quit = 1; 45 | break; 46 | } 47 | if (event.type == SDL_KEYDOWN) { 48 | if (event.key.keysym.sym == SDLK_ESCAPE) { 49 | quit = 1; 50 | break; 51 | } 52 | } 53 | } 54 | if (quit) 55 | break; 56 | SDL_Rect rect; 57 | rect.x = 0; 58 | rect.y = 0; 59 | rect.w = w; 60 | rect.h = h; 61 | Uint32 col = SDL_MapRGB(screen->format, 255, 255, 255); 62 | SDL_FillRect(screen, &rect, col); 63 | 64 | rect.x = ballx; 65 | rect.y = bally; 66 | rect.w = balld; 67 | rect.h = balld; 68 | col = SDL_MapRGB(screen->format, 255, 0, 0); 69 | SDL_FillRect(screen, &rect, col); 70 | ballx += balldir; 71 | if (balldir == 1) { 72 | if (ballx >= w - balld) { 73 | balldir = -1; 74 | } 75 | } else { 76 | if (ballx <= 0) { 77 | balldir = 1; 78 | } 79 | } 80 | 81 | #ifdef SDL1 82 | SDL_UpdateRect(screen, 0, 0, 0, 0); 83 | #else 84 | SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch); 85 | SDL_RenderClear(sdlRenderer); 86 | SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); 87 | SDL_RenderPresent(sdlRenderer); 88 | #endif 89 | SDL_Delay(10); 90 | } 91 | printf("bye\n"); 92 | 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /shaders/text.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | in vec2 TexCoords; 3 | out vec4 color; 4 | 5 | uniform sampler2D text; 6 | uniform vec3 textColor; 7 | 8 | void main() 9 | { 10 | vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r); 11 | color = vec4(textColor, 1.0) * sampled; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /shaders/text.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | layout (location = 0) in vec4 vertex; // 3 | out vec2 TexCoords; 4 | 5 | uniform mat4 projection; 6 | 7 | void main() 8 | { 9 | gl_Position = projection * vec4(vertex.xy, 0.0, 1.0); 10 | TexCoords = vertex.zw; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /sounds/LICENSE: -------------------------------------------------------------------------------- 1 | This work has been identified as being free of known restrictions under copyright law, including all related and neighboring rights. 2 | 3 | You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. 4 | -------------------------------------------------------------------------------- /sounds/SuperTwintrisThoseThree.mod: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/sounds/SuperTwintrisThoseThree.mod -------------------------------------------------------------------------------- /sounds/TwintrisAudiokraft.mod: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/sounds/TwintrisAudiokraft.mod -------------------------------------------------------------------------------- /sounds/TwintrisThosenine.mod: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/sounds/TwintrisThosenine.mod -------------------------------------------------------------------------------- /sounds/TwintrisWerethedevils.mod: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/sounds/TwintrisWerethedevils.mod -------------------------------------------------------------------------------- /sounds/block.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/sounds/block.wav -------------------------------------------------------------------------------- /sounds/door1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/sounds/door1.wav -------------------------------------------------------------------------------- /sounds/door2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/sounds/door2.wav -------------------------------------------------------------------------------- /sounds/double.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/sounds/double.wav -------------------------------------------------------------------------------- /sounds/line.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/sounds/line.wav -------------------------------------------------------------------------------- /sounds/single.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/sounds/single.wav -------------------------------------------------------------------------------- /sounds/triple.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/sounds/triple.wav -------------------------------------------------------------------------------- /tetris_v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/tetris_v.png -------------------------------------------------------------------------------- /tetris_v.v: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 Alexander Medvednikov. All rights reserved. 2 | // Use of this source code is governed by an MIT license 3 | // that can be found in the LICENSE file. 4 | 5 | // Ported to SDL2 V wrapper by Nicolas Sauzede 2019 6 | 7 | import rand 8 | import time 9 | import math 10 | import vsdl 11 | 12 | const ( 13 | Title = 'V Tetris' 14 | FontName = 'fonts/RobotoMono-Regular.ttf' 15 | BlockSize = 20 // pixels 16 | FieldHeight = 20 // # of blocks 17 | FieldWidth = 10 18 | TetroSize = 4 19 | WinWidth = BlockSize * FieldWidth 20 | WinHeight = BlockSize * FieldHeight 21 | TimerPeriod = 250 // ms 22 | TextSize = 16 23 | AudioBufSize = 1024 24 | ) 25 | 26 | const ( 27 | // Tetros' 4 possible states are encoded in binaries 28 | BTetros = [ 29 | // 0000 0 30 | // 0000 0 31 | // 0110 6 32 | // 0110 6 33 | [66, 66, 66, 66], 34 | // 0000 0 35 | // 0000 0 36 | // 0010 2 37 | // 0111 7 38 | [27, 131, 72, 232], 39 | // 0000 0 40 | // 0000 0 41 | // 0011 3 42 | // 0110 6 43 | [36, 231, 36, 231], 44 | // 0000 0 45 | // 0000 0 46 | // 0110 6 47 | // 0011 3 48 | [63, 132, 63, 132], 49 | // 0000 0 50 | // 0011 3 51 | // 0001 1 52 | // 0001 1 53 | [311, 17, 223, 74], 54 | // 0000 0 55 | // 0011 3 56 | // 0010 2 57 | // 0010 2 58 | [322, 71, 113, 47], 59 | // Special case since 15 can't be used 60 | // 1111 61 | [1111, 9, 1111, 9], 62 | ] 63 | // Each tetro has its unique color 64 | Colors = [ 65 | SdlColor{byte(0), byte(0), byte(0), byte(0)}, // unused ? 66 | SdlColor{byte(0), byte(0x62), byte(0xc0), byte(0)}, // quad : darkblue 0062c0 67 | SdlColor{byte(0xca), byte(0x7d), byte(0x5f), byte(0)}, // tricorn : lightbrown ca7d5f 68 | SdlColor{byte(0), byte(0xc1), byte(0xbf), byte(0)}, // short topright : lightblue 00c1bf 69 | SdlColor{byte(0), byte(0xc1), byte(0), byte(0)}, // short topleft : lightgreen 00c100 70 | SdlColor{byte(0xbf), byte(0xbe), byte(0), byte(0)}, // long topleft : yellowish bfbe00 71 | SdlColor{byte(0xd1), byte(0), byte(0xbf), byte(0)}, // long topright : pink d100bf 72 | SdlColor{byte(0xd1), byte(0), byte(0), byte(0)}, // longest : lightred d10000 73 | SdlColor{byte(0), byte(170), byte(170), byte(0)}, // unused ? 74 | ] 75 | ) 76 | 77 | // TODO: type Tetro [TetroSize]struct{ x, y int } 78 | struct Block { 79 | mut: 80 | x int 81 | y int 82 | } 83 | 84 | enum GameState { 85 | paused running gameover 86 | } 87 | 88 | struct AudioContext { 89 | mut: 90 | // music *C.Mix_Music 91 | music voidptr 92 | volume int 93 | // waves [3]*MixChunk 94 | waves [3]voidptr 95 | } 96 | 97 | struct SdlContext { 98 | mut: 99 | // VIDEO 100 | w int 101 | h int 102 | window voidptr 103 | renderer voidptr 104 | screen &vsdl2.SdlSurface 105 | texture voidptr 106 | // AUDIO 107 | actx AudioContext 108 | } 109 | 110 | struct Game { 111 | mut: 112 | // Score of the current game 113 | score int 114 | // Count consecutive lines for scoring 115 | lines int 116 | // State of the current game 117 | state GameState 118 | // Quit game ? 119 | should_close bool 120 | // Position of the current tetro 121 | pos_x int 122 | pos_y int 123 | // field[y][x] contains the color of the block with (x,y) coordinates 124 | // "-1" border is to avoid bounds checking. 125 | // -1 -1 -1 -1 126 | // -1 0 0 -1 127 | // -1 0 0 -1 128 | // -1 -1 -1 -1 129 | field [][]int 130 | // TODO: tetro Tetro 131 | tetro []Block 132 | // TODO: tetros_cache []Tetro 133 | tetros_cache []Block 134 | // Index of the current tetro. Refers to its color. 135 | tetro_idx int 136 | // Index of the next tetro. Refers to its color. 137 | tetro_next int 138 | // Index of the rotation (0-3) 139 | rotation_idx int 140 | // SDL2 context for drawing 141 | sdl SdlContext 142 | // TTF context for font drawing 143 | font voidptr 144 | } 145 | 146 | fn (sdl mut SdlContext) set_sdl_context(w int, h int, title string) { 147 | C.SDL_Init(C.SDL_INIT_VIDEO | C.SDL_INIT_AUDIO) 148 | C.atexit(C.SDL_Quit) 149 | C.TTF_Init() 150 | C.atexit(C.TTF_Quit) 151 | bpp := 32 152 | C.SDL_CreateWindowAndRenderer(w, h, 0, &sdl.window, &sdl.renderer) 153 | C.SDL_SetWindowTitle(sdl.window, title.str) 154 | sdl.w = w 155 | sdl.h = h 156 | sdl.screen = &vsdl2.SdlSurface(C.SDL_CreateRGBSurface(0, w, h, bpp, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000)) 157 | sdl.texture = C.SDL_CreateTexture(sdl.renderer, C.SDL_PIXELFORMAT_ARGB8888, C.SDL_TEXTUREACCESS_STREAMING, w, h) 158 | 159 | C.Mix_Init(0) 160 | C.atexit(C.Mix_Quit) 161 | if C.Mix_OpenAudio(48000,C.MIX_DEFAULT_FORMAT,2,AudioBufSize) < 0 { 162 | println('couldn\'t open audio') 163 | } 164 | sdl.actx.music = C.Mix_LoadMUS('sounds/TwintrisThosenine.mod') 165 | sdl.actx.waves[0] = C.Mix_LoadWAV('sounds/block.wav') 166 | sdl.actx.waves[1] = C.Mix_LoadWAV('sounds/line.wav') 167 | sdl.actx.waves[2] = C.Mix_LoadWAV('sounds/double.wav') 168 | sdl.actx.volume = C.SDL_MIX_MAXVOLUME 169 | if C.Mix_PlayMusic(sdl.actx.music, 1) != -1 { 170 | C.Mix_VolumeMusic(sdl.actx.volume) 171 | } 172 | } 173 | 174 | fn main() { 175 | println('V Tetris -- with Colors, Sounds & Music borrowed from venerable Twintris') 176 | println('vsdl.version: $vsdl.version') 177 | mut game := &Game{} 178 | game.sdl.set_sdl_context(WinWidth, WinHeight, Title) 179 | game.font = C.TTF_OpenFont(FontName.str, TextSize) 180 | game.init_game() 181 | go game.run() // Run the game loop in a new thread 182 | for { 183 | game.draw_scene() 184 | // game.handle_events() // CRASHES if done in function ??? 185 | ev := SdlEvent{} 186 | for 0 < C.SDL_PollEvent(&ev) { 187 | switch ev._type { 188 | case C.SDL_QUIT: 189 | game.should_close = true 190 | break 191 | case C.SDL_KEYDOWN: 192 | // global keys 193 | switch int(ev.key.keysym.sym) { 194 | case C.SDLK_ESCAPE: 195 | game.should_close = true 196 | break 197 | case C.SDLK_SPACE: 198 | switch game.state { 199 | case .running: 200 | game.state = .paused 201 | case .paused: 202 | game.state = .running 203 | case .gameover: 204 | game.init_game() 205 | game.state = .running 206 | } 207 | } 208 | if game.state != .running { 209 | break 210 | } 211 | // keys while game is running 212 | switch int(ev.key.keysym.sym) { 213 | case C.SDLK_UP: 214 | // Rotate the tetro 215 | old_rotation_idx := game.rotation_idx 216 | game.rotation_idx++ 217 | if game.rotation_idx == TetroSize { 218 | game.rotation_idx = 0 219 | } 220 | game.get_tetro() 221 | if !game.move_right(0) { 222 | game.rotation_idx = old_rotation_idx 223 | game.get_tetro() 224 | } 225 | if game.pos_x < 0 { 226 | game.pos_x = 1 227 | } 228 | case C.SDLK_LEFT: 229 | game.move_right(-1) 230 | case C.SDLK_RIGHT: 231 | game.move_right(1) 232 | case C.SDLK_DOWN: 233 | game.move_tetro() // drop faster when the player presses 234 | } 235 | } 236 | } 237 | if game.should_close { 238 | break 239 | } 240 | C.SDL_Delay(20) // short delay between redraw 241 | } 242 | if game.font != voidptr(0) { 243 | C.TTF_CloseFont(game.font) 244 | } 245 | if game.sdl.actx.music != voidptr(0) { 246 | C.Mix_FreeMusic(game.sdl.actx.music) 247 | } 248 | C.Mix_CloseAudio() 249 | if game.sdl.actx.waves[0] != voidptr(0) { 250 | C.Mix_FreeChunk(game.sdl.actx.waves[0]) 251 | } 252 | if game.sdl.actx.waves[1] != voidptr(0) { 253 | C.Mix_FreeChunk(game.sdl.actx.waves[1]) 254 | } 255 | if game.sdl.actx.waves[2] != voidptr(0) { 256 | C.Mix_FreeChunk(game.sdl.actx.waves[2]) 257 | } 258 | } 259 | 260 | fn (g mut Game) init_game() { 261 | g.parse_tetros() 262 | rand.seed(time.now().unix) 263 | g.generate_tetro() 264 | g.field = []array_int // TODO: g.field = [][]int 265 | // Generate the field, fill it with 0's, add -1's on each edge 266 | for i := 0; i < FieldHeight + 2; i++ { 267 | mut row := [0].repeat(FieldWidth + 2) 268 | row[0] = - 1 269 | row[FieldWidth + 1] = - 1 270 | g.field << row 271 | } 272 | mut first_row := g.field[0] 273 | mut last_row := g.field[FieldHeight + 1] 274 | for j := 0; j < FieldWidth + 2; j++ { 275 | first_row[j] = - 1 276 | last_row[j] = - 1 277 | } 278 | g.score = 0 279 | g.state = .running 280 | } 281 | 282 | fn (g mut Game) parse_tetros() { 283 | for b_tetros in BTetros { 284 | for b_tetro in b_tetros { 285 | for t in parse_binary_tetro(b_tetro) { 286 | g.tetros_cache << t 287 | } 288 | } 289 | } 290 | } 291 | 292 | fn (g mut Game) run() { 293 | for { 294 | if g.state == .running { 295 | g.move_tetro() 296 | n := g.delete_completed_lines() 297 | if n > 0 { 298 | g.lines += n 299 | } else { 300 | if g.lines > 0 { 301 | if g.lines > 1 { 302 | C.Mix_PlayChannel(0, g.sdl.actx.waves[2], 0) 303 | } else if g.lines == 1 { 304 | C.Mix_PlayChannel(0, g.sdl.actx.waves[1], 0) 305 | } 306 | g.score += 10 * g.lines * g.lines 307 | g.lines = 0 308 | } 309 | } 310 | } 311 | time.sleep_ms(TimerPeriod) // medium delay between game step 312 | } 313 | } 314 | 315 | fn (g mut Game) move_tetro() { 316 | // Check each block in current tetro 317 | for block in g.tetro { 318 | y := block.y + g.pos_y + 1 319 | x := block.x + g.pos_x 320 | // Reached the bottom of the screen or another block? 321 | // TODO: if g.field[y][x] != 0 322 | //if g.field[y][x] != 0 { 323 | row := g.field[y] 324 | if row[x] != 0 { 325 | // The new tetro has no space to drop => end of the game 326 | if g.pos_y < 2 { 327 | g.state = .gameover 328 | return 329 | } 330 | // Drop it and generate a new one 331 | g.drop_tetro() 332 | g.generate_tetro() 333 | C.Mix_PlayChannel(0, g.sdl.actx.waves[0], 0) 334 | return 335 | } 336 | } 337 | g.pos_y++ 338 | } 339 | 340 | fn (g mut Game) move_right(dx int) bool { 341 | // Reached left/right edge or another tetro? 342 | for i := 0; i < TetroSize; i++ { 343 | tetro := g.tetro[i] 344 | y := tetro.y + g.pos_y 345 | x := tetro.x + g.pos_x + dx 346 | row := g.field[y] 347 | if row[x] != 0 { 348 | // Do not move 349 | return false 350 | } 351 | } 352 | g.pos_x += dx 353 | return true 354 | } 355 | 356 | fn (g &Game) delete_completed_lines() int { 357 | mut n := 0 358 | for y := FieldHeight; y >= 1; y-- { 359 | n += g.delete_completed_line(y) 360 | } 361 | return n 362 | } 363 | 364 | fn (g &Game) delete_completed_line(y int) int { 365 | for x := 1; x <= FieldWidth; x++ { 366 | f := g.field[y] 367 | if f[x] == 0 { 368 | return 0 369 | } 370 | } 371 | // Move everything down by 1 position 372 | for yy := y - 1; yy >= 1; yy-- { 373 | for x := 1; x <= FieldWidth; x++ { 374 | mut a := g.field[yy + 1] 375 | b := g.field[yy] 376 | a[x] = b[x] 377 | } 378 | } 379 | return 1 380 | } 381 | 382 | // Draw a rand tetro index 383 | fn (g mut Game) rand_tetro() int { 384 | cur := g.tetro_next 385 | g.tetro_next = rand.next(BTetros.len) 386 | return cur 387 | } 388 | 389 | // Place a new tetro on top 390 | fn (g mut Game) generate_tetro() { 391 | g.pos_y = 0 392 | g.pos_x = FieldWidth / 2 - TetroSize / 2 393 | g.tetro_idx = g.rand_tetro() 394 | g.rotation_idx = 0 395 | g.get_tetro() 396 | } 397 | 398 | // Get the right tetro from cache 399 | fn (g mut Game) get_tetro() { 400 | idx := g.tetro_idx * TetroSize * TetroSize + g.rotation_idx * TetroSize 401 | g.tetro = g.tetros_cache.slice(idx, idx + TetroSize) 402 | } 403 | 404 | fn (g &Game) drop_tetro() { 405 | for i := 0; i < TetroSize; i++ { 406 | tetro := g.tetro[i] 407 | x := tetro.x + g.pos_x 408 | y := tetro.y + g.pos_y 409 | // Remember the color of each block 410 | // TODO: g.field[y][x] = g.tetro_idx + 1 411 | mut row := g.field[y] 412 | row[x] = g.tetro_idx + 1 413 | } 414 | } 415 | 416 | fn (g &Game) draw_block(i, j, color_idx int) { 417 | rect := vsdl2.SdlRect {(j - 1) * BlockSize, (i - 1) * BlockSize, 418 | BlockSize - 1, BlockSize - 1} 419 | scol := Colors[color_idx] 420 | rr := scol.r 421 | gg := scol.g 422 | bb := scol.b 423 | col := C.SDL_MapRGB(g.sdl.screen.format, rr, gg, bb) 424 | C.SDL_FillRect(g.sdl.screen, &rect, col) 425 | } 426 | 427 | fn (g &Game) draw_text(x int, y int, text string, rr int, gg int, bb int) { 428 | tcol := SdlColor {byte(3), byte(2), byte(1), byte(0)} 429 | tsurf := C.TTF_RenderText_Solid(g.font, text.str, tcol) 430 | ttext := C.SDL_CreateTextureFromSurface(g.sdl.renderer, tsurf) 431 | texw := 0 432 | texh := 0 433 | C.SDL_QueryTexture(ttext, 0, 0, &texw, &texh) 434 | dstrect := vsdl2.SdlRect { x, y, texw, texh } 435 | C.SDL_RenderCopy(g.sdl.renderer, ttext, 0, &dstrect) 436 | C.SDL_DestroyTexture(ttext) 437 | vsdl2.free_surface(tsurf) 438 | } 439 | 440 | fn (g &Game) draw_tetro() { 441 | for i := 0; i < TetroSize; i++ { 442 | tetro := g.tetro[i] 443 | g.draw_block(g.pos_y + tetro.y, g.pos_x + tetro.x, g.tetro_idx + 1) 444 | } 445 | } 446 | 447 | fn (g &Game) draw_field() { 448 | for i := 1; i < FieldHeight + 1; i++ { 449 | for j := 1; j < FieldWidth + 1; j++ { 450 | f := g.field[i] 451 | if f[j] > 0 { 452 | g.draw_block(i, j, f[j]) 453 | } 454 | } 455 | } 456 | } 457 | 458 | fn (g &Game) draw_score() { 459 | if g.font != voidptr(0) { 460 | g.draw_text(1, 2, 'score: ' + g.score.str() + ' nxt=' + g.tetro_next.str(), 0, 0, 0) 461 | if g.state == .gameover { 462 | g.draw_text(1, WinHeight / 2 + 0 * TextSize, 'Game Over', 0, 0, 0) 463 | g.draw_text(1, WinHeight / 2 + 2 * TextSize, 'SPACE to restart', 0, 0, 0) 464 | } else if g.state == .paused { 465 | g.draw_text(1, WinHeight / 2 + 0 * TextSize, 'Game Paused', 0, 0, 0) 466 | g.draw_text(1, WinHeight / 2 + 2 * TextSize, 'SPACE to resume', 0, 0, 0) 467 | } 468 | } 469 | } 470 | 471 | fn (g &Game) draw_scene() { 472 | rect := vsdl2.SdlRect {0,0,g.sdl.w,g.sdl.h} 473 | col := C.SDL_MapRGB(g.sdl.screen.format, 255, 255, 255) 474 | C.SDL_FillRect(g.sdl.screen, &rect, col) 475 | 476 | g.draw_tetro() 477 | g.draw_field() 478 | 479 | C.SDL_UpdateTexture(g.sdl.texture, 0, g.sdl.screen.pixels, g.sdl.screen.pitch) 480 | C.SDL_RenderClear(g.sdl.renderer) 481 | C.SDL_RenderCopy(g.sdl.renderer, g.sdl.texture, 0, 0) 482 | 483 | g.draw_score() 484 | 485 | C.SDL_RenderPresent(g.sdl.renderer) 486 | } 487 | 488 | fn parse_binary_tetro(t_ int) []Block { 489 | mut t := t_ 490 | res := [Block{}].repeat(4) 491 | mut cnt := 0 492 | horizontal := t == 9// special case for the horizontal line 493 | for i := 0; i <= 3; i++ { 494 | // Get ith digit of t 495 | p := int(math.pow(10, 3 - i)) 496 | mut digit := int(t / p) 497 | t %= p 498 | // Convert the digit to binary 499 | for j := 3; j >= 0; j-- { 500 | bin := digit % 2 501 | digit /= 2 502 | if bin == 1 || (horizontal && i == TetroSize - 1) { 503 | // TODO: res[cnt].x = j 504 | // res[cnt].y = i 505 | mut point := &res[cnt] 506 | point.x = j 507 | point.y = i 508 | cnt++ 509 | } 510 | } 511 | } 512 | return res 513 | } 514 | -------------------------------------------------------------------------------- /tetrisnomix_v.v: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 Alexander Medvednikov. All rights reserved. 2 | // Use of this source code is governed by an MIT license 3 | // that can be found in the LICENSE file. 4 | 5 | // Ported to SDL2 V wrapper by Nicolas Sauzede 2019 6 | 7 | import rand 8 | import time 9 | import math 10 | import vsdl 11 | 12 | const ( 13 | Title = 'V Tetris' 14 | FontName = 'fonts/RobotoMono-Regular.ttf' 15 | BlockSize = 20 // pixels 16 | FieldHeight = 20 // # of blocks 17 | FieldWidth = 10 18 | TetroSize = 4 19 | WinWidth = BlockSize * FieldWidth 20 | WinHeight = BlockSize * FieldHeight 21 | TimerPeriod = 250 // ms 22 | TextSize = 16 23 | ) 24 | 25 | const ( 26 | // Tetros' 4 possible states are encoded in binaries 27 | BTetros = [ 28 | // 0000 0 29 | // 0000 0 30 | // 0110 6 31 | // 0110 6 32 | [66, 66, 66, 66], 33 | // 0000 0 34 | // 0000 0 35 | // 0010 2 36 | // 0111 7 37 | [27, 131, 72, 232], 38 | // 0000 0 39 | // 0000 0 40 | // 0011 3 41 | // 0110 6 42 | [36, 231, 36, 231], 43 | // 0000 0 44 | // 0000 0 45 | // 0110 6 46 | // 0011 3 47 | [63, 132, 63, 132], 48 | // 0000 0 49 | // 0011 3 50 | // 0001 1 51 | // 0001 1 52 | [311, 17, 223, 74], 53 | // 0000 0 54 | // 0011 3 55 | // 0010 2 56 | // 0010 2 57 | [322, 71, 113, 47], 58 | // Special case since 15 can't be used 59 | // 1111 60 | [1111, 9, 1111, 9], 61 | ] 62 | // Each tetro has its unique color 63 | Colors = [ 64 | SdlColor{byte(0), byte(0), byte(0), byte(0)}, // unused ? 65 | SdlColor{byte(253), byte(32), byte(47), byte(0)}, // lightred quad 66 | SdlColor{byte(0), byte(110), byte(194), byte(0)}, // lightblue triple 67 | SdlColor{byte(170), byte(170), byte(0), byte(0)}, // darkyellow short topright 68 | SdlColor{byte(170), byte(0), byte(170), byte(0)}, // purple short topleft 69 | SdlColor{byte(50), byte(90), byte(110), byte(0)}, // darkgrey long topleft 70 | SdlColor{byte(0), byte(170), byte(0), byte(0)}, // lightgreen long topright 71 | SdlColor{byte(170), byte(85), byte(0), byte(0)}, // brown longest 72 | SdlColor{byte(0), byte(170), byte(170), byte(0)}, // unused ? 73 | ] 74 | ) 75 | 76 | // TODO: type Tetro [TetroSize]struct{ x, y int } 77 | struct Block { 78 | mut: 79 | x int 80 | y int 81 | } 82 | 83 | enum GameState { 84 | paused running gameover 85 | } 86 | 87 | struct AudioSample { 88 | wav_buffer &byte 89 | wav_length u32 90 | } 91 | 92 | struct AudioContext { 93 | mut: 94 | // audio_pos *byte 95 | audio_pos voidptr 96 | audio_len u32 97 | wav_spec SdlAudioSpec 98 | samples [3]AudioSample 99 | } 100 | 101 | struct SdlContext { 102 | mut: 103 | // VIDEO 104 | w int 105 | h int 106 | window voidptr 107 | renderer voidptr 108 | screen &SdlSurface 109 | texture voidptr 110 | // AUDIO 111 | actx AudioContext 112 | } 113 | 114 | struct Game { 115 | mut: 116 | // Score of the current game 117 | score int 118 | // Count consecutive lines for scoring 119 | lines int 120 | // State of the current game 121 | state GameState 122 | // Quit game ? 123 | should_close bool 124 | // Position of the current tetro 125 | pos_x int 126 | pos_y int 127 | // field[y][x] contains the color of the block with (x,y) coordinates 128 | // "-1" border is to avoid bounds checking. 129 | // -1 -1 -1 -1 130 | // -1 0 0 -1 131 | // -1 0 0 -1 132 | // -1 -1 -1 -1 133 | field [][]int 134 | // TODO: tetro Tetro 135 | tetro []Block 136 | // TODO: tetros_cache []Tetro 137 | tetros_cache []Block 138 | // Index of the current tetro. Refers to its color. 139 | tetro_idx int 140 | // Index of the next tetro. Refers to its color. 141 | tetro_next int 142 | // Index of the rotation (0-3) 143 | rotation_idx int 144 | // SDL2 context for drawing 145 | sdl SdlContext 146 | // TTF context for font drawing 147 | font voidptr 148 | } 149 | 150 | fn acb(userdata voidptr, stream &byte, _len int) { 151 | mut ctx := &AudioContext(userdata) 152 | C.memset(stream, 0, _len) 153 | if ctx.audio_len == u32(0) { 154 | return 155 | } 156 | mut len := u32(_len) 157 | if len > ctx.audio_len { len = ctx.audio_len } 158 | C.memcpy(stream, ctx.audio_pos, len) 159 | ctx.audio_pos += len 160 | ctx.audio_len -= len 161 | } 162 | 163 | fn (sdl mut SdlContext) set_sdl_context(w int, h int, title string) { 164 | C.SDL_Init(C.SDL_INIT_VIDEO | C.SDL_INIT_AUDIO) 165 | C.atexit(C.SDL_Quit) 166 | C.TTF_Init() 167 | C.atexit(C.TTF_Quit) 168 | bpp := 32 169 | C.SDL_CreateWindowAndRenderer(w, h, 0, &sdl.window, &sdl.renderer) 170 | C.SDL_SetWindowTitle(sdl.window, title.str) 171 | sdl.w = w 172 | sdl.h = h 173 | sdl.screen = &SdlSurface(C.SDL_CreateRGBSurface(0, w, h, bpp, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000)) 174 | sdl.texture = C.SDL_CreateTexture(sdl.renderer, C.SDL_PIXELFORMAT_ARGB8888, C.SDL_TEXTUREACCESS_STREAMING, w, h) 175 | 176 | C.SDL_LoadWAV('sounds/block.wav', &sdl.actx.wav_spec, &sdl.actx.samples[0].wav_buffer, &sdl.actx.samples[0].wav_length) 177 | C.SDL_LoadWAV('sounds/line.wav', &sdl.actx.wav_spec, &sdl.actx.samples[1].wav_buffer, &sdl.actx.samples[1].wav_length) 178 | C.SDL_LoadWAV('sounds/double.wav', &sdl.actx.wav_spec, &sdl.actx.samples[2].wav_buffer, &sdl.actx.samples[2].wav_length) 179 | sdl.actx.wav_spec.callback = acb 180 | sdl.actx.wav_spec.userdata = &sdl.actx 181 | sdl.actx.audio_len = u32(0) 182 | sdl.actx.audio_pos = voidptr(0) 183 | if C.SDL_OpenAudio(&sdl.actx.wav_spec, 0) < 0 { 184 | println('couldn\'t open audio') 185 | } else { 186 | C.SDL_PauseAudio(0) 187 | } 188 | } 189 | 190 | fn main() { 191 | mut game := &Game{} 192 | game.sdl.set_sdl_context(WinWidth, WinHeight, Title) 193 | game.font = C.TTF_OpenFont(FontName.str, TextSize) 194 | game.init_game() 195 | go game.run() // Run the game loop in a new thread 196 | for { 197 | game.draw_scene() 198 | // game.handle_events() // CRASHES if done in function ??? 199 | ev := SdlEvent{} 200 | for 0 < C.SDL_PollEvent(&ev) { 201 | switch ev._type { 202 | case C.SDL_QUIT: 203 | game.should_close = true 204 | break 205 | case C.SDL_KEYDOWN: 206 | // global keys 207 | switch int(ev.key.keysym.sym) { 208 | case C.SDLK_ESCAPE: 209 | game.should_close = true 210 | break 211 | case C.SDLK_SPACE: 212 | switch game.state { 213 | case .running: 214 | game.state = .paused 215 | case .paused: 216 | game.state = .running 217 | case .gameover: 218 | game.init_game() 219 | game.state = .running 220 | } 221 | } 222 | if game.state != .running { 223 | break 224 | } 225 | // keys while game is running 226 | switch int(ev.key.keysym.sym) { 227 | case C.SDLK_UP: 228 | // Rotate the tetro 229 | old_rotation_idx := game.rotation_idx 230 | game.rotation_idx++ 231 | if game.rotation_idx == TetroSize { 232 | game.rotation_idx = 0 233 | } 234 | game.get_tetro() 235 | if !game.move_right(0) { 236 | game.rotation_idx = old_rotation_idx 237 | game.get_tetro() 238 | } 239 | if game.pos_x < 0 { 240 | game.pos_x = 1 241 | } 242 | case C.SDLK_LEFT: 243 | game.move_right(-1) 244 | case C.SDLK_RIGHT: 245 | game.move_right(1) 246 | case C.SDLK_DOWN: 247 | game.move_tetro() // drop faster when the player presses 248 | } 249 | } 250 | } 251 | if game.should_close { 252 | break 253 | } 254 | C.SDL_Delay(20) // short delay between redraw 255 | } 256 | if game.font != voidptr(0) { 257 | C.TTF_CloseFont(game.font) 258 | } 259 | } 260 | 261 | fn (g &Game) draw_scene() { 262 | rect := SdlRect {0,0,g.sdl.w,g.sdl.h} 263 | col := C.SDL_MapRGB(g.sdl.screen.format, 255, 255, 255) 264 | C.SDL_FillRect(g.sdl.screen, &rect, col) 265 | 266 | g.draw_tetro() 267 | g.draw_field() 268 | 269 | C.SDL_UpdateTexture(g.sdl.texture, 0, g.sdl.screen.pixels, g.sdl.screen.pitch) 270 | C.SDL_RenderClear(g.sdl.renderer) 271 | C.SDL_RenderCopy(g.sdl.renderer, g.sdl.texture, 0, 0) 272 | 273 | g.draw_score() 274 | 275 | C.SDL_RenderPresent(g.sdl.renderer) 276 | } 277 | 278 | fn (g mut Game) init_game() { 279 | g.parse_tetros() 280 | rand.seed(time.now().unix) 281 | g.generate_tetro() 282 | g.field = []array_int // TODO: g.field = [][]int 283 | // Generate the field, fill it with 0's, add -1's on each edge 284 | for i := 0; i < FieldHeight + 2; i++ { 285 | mut row := [0].repeat(FieldWidth + 2) 286 | row[0] = - 1 287 | row[FieldWidth + 1] = - 1 288 | g.field << row 289 | } 290 | mut first_row := g.field[0] 291 | mut last_row := g.field[FieldHeight + 1] 292 | for j := 0; j < FieldWidth + 2; j++ { 293 | first_row[j] = - 1 294 | last_row[j] = - 1 295 | } 296 | g.score = 0 297 | g.state = .running 298 | } 299 | 300 | fn (g mut Game) parse_tetros() { 301 | for b_tetros in BTetros { 302 | for b_tetro in b_tetros { 303 | for t in parse_binary_tetro(b_tetro) { 304 | g.tetros_cache << t 305 | } 306 | } 307 | } 308 | } 309 | 310 | fn (g mut Game) run() { 311 | for { 312 | if g.state == .running { 313 | g.move_tetro() 314 | n := g.delete_completed_lines() 315 | if n > 0 { 316 | g.lines += n 317 | } else { 318 | if g.lines > 0 { 319 | if g.lines > 1 { 320 | g.sdl.actx.audio_pos = g.sdl.actx.samples[2].wav_buffer 321 | g.sdl.actx.audio_len = g.sdl.actx.samples[2].wav_length 322 | } else if g.lines == 1 { 323 | g.sdl.actx.audio_pos = g.sdl.actx.samples[1].wav_buffer 324 | g.sdl.actx.audio_len = g.sdl.actx.samples[1].wav_length 325 | } 326 | g.score += 10 * g.lines * g.lines 327 | g.lines = 0 328 | } 329 | } 330 | } 331 | time.sleep_ms(TimerPeriod) // medium delay between game step 332 | } 333 | } 334 | 335 | fn (g mut Game) move_tetro() { 336 | // Check each block in current tetro 337 | for block in g.tetro { 338 | y := block.y + g.pos_y + 1 339 | x := block.x + g.pos_x 340 | // Reached the bottom of the screen or another block? 341 | // TODO: if g.field[y][x] != 0 342 | //if g.field[y][x] != 0 { 343 | row := g.field[y] 344 | if row[x] != 0 { 345 | // The new tetro has no space to drop => end of the game 346 | if g.pos_y < 2 { 347 | g.state = .gameover 348 | return 349 | } 350 | // Drop it and generate a new one 351 | g.drop_tetro() 352 | g.generate_tetro() 353 | g.sdl.actx.audio_pos = g.sdl.actx.samples[0].wav_buffer 354 | g.sdl.actx.audio_len = g.sdl.actx.samples[0].wav_length 355 | return 356 | } 357 | } 358 | g.pos_y++ 359 | } 360 | 361 | fn (g mut Game) move_right(dx int) bool { 362 | // Reached left/right edge or another tetro? 363 | for i := 0; i < TetroSize; i++ { 364 | tetro := g.tetro[i] 365 | y := tetro.y + g.pos_y 366 | x := tetro.x + g.pos_x + dx 367 | row := g.field[y] 368 | if row[x] != 0 { 369 | // Do not move 370 | return false 371 | } 372 | } 373 | g.pos_x += dx 374 | return true 375 | } 376 | 377 | fn (g &Game) delete_completed_lines() int { 378 | mut n := 0 379 | for y := FieldHeight; y >= 1; y-- { 380 | n += g.delete_completed_line(y) 381 | } 382 | return n 383 | } 384 | 385 | fn (g &Game) delete_completed_line(y int) int { 386 | for x := 1; x <= FieldWidth; x++ { 387 | f := g.field[y] 388 | if f[x] == 0 { 389 | return 0 390 | } 391 | } 392 | // Move everything down by 1 position 393 | for yy := y - 1; yy >= 1; yy-- { 394 | for x := 1; x <= FieldWidth; x++ { 395 | mut a := g.field[yy + 1] 396 | b := g.field[yy] 397 | a[x] = b[x] 398 | } 399 | } 400 | return 1 401 | } 402 | 403 | // Draw a rand tetro index 404 | fn (g mut Game) rand_tetro() int { 405 | cur := g.tetro_next 406 | g.tetro_next = rand.next(BTetros.len) 407 | return cur 408 | } 409 | 410 | // Place a new tetro on top 411 | fn (g mut Game) generate_tetro() { 412 | g.pos_y = 0 413 | g.pos_x = FieldWidth / 2 - TetroSize / 2 414 | g.tetro_idx = g.rand_tetro() 415 | g.rotation_idx = 0 416 | g.get_tetro() 417 | } 418 | 419 | // Get the right tetro from cache 420 | fn (g mut Game) get_tetro() { 421 | idx := g.tetro_idx * TetroSize * TetroSize + g.rotation_idx * TetroSize 422 | g.tetro = g.tetros_cache.slice(idx, idx + TetroSize) 423 | } 424 | 425 | fn (g &Game) drop_tetro() { 426 | for i := 0; i < TetroSize; i++ { 427 | tetro := g.tetro[i] 428 | x := tetro.x + g.pos_x 429 | y := tetro.y + g.pos_y 430 | // Remember the color of each block 431 | // TODO: g.field[y][x] = g.tetro_idx + 1 432 | mut row := g.field[y] 433 | row[x] = g.tetro_idx + 1 434 | } 435 | } 436 | 437 | fn (g &Game) draw_tetro() { 438 | for i := 0; i < TetroSize; i++ { 439 | tetro := g.tetro[i] 440 | g.draw_block(g.pos_y + tetro.y, g.pos_x + tetro.x, g.tetro_idx + 1) 441 | } 442 | } 443 | 444 | fn (g &Game) draw_block(i, j, color_idx int) { 445 | rect := SdlRect {(j - 1) * BlockSize, (i - 1) * BlockSize, 446 | BlockSize - 1, BlockSize - 1} 447 | scol := Colors[color_idx] 448 | rr := scol.r 449 | gg := scol.g 450 | bb := scol.b 451 | col := C.SDL_MapRGB(g.sdl.screen.format, rr, gg, bb) 452 | C.SDL_FillRect(g.sdl.screen, &rect, col) 453 | } 454 | 455 | fn (g &Game) draw_field() { 456 | for i := 1; i < FieldHeight + 1; i++ { 457 | for j := 1; j < FieldWidth + 1; j++ { 458 | f := g.field[i] 459 | if f[j] > 0 { 460 | g.draw_block(i, j, f[j]) 461 | } 462 | } 463 | } 464 | } 465 | 466 | fn (g &Game) draw_text(x int, y int, text string, rr int, gg int, bb int) { 467 | tcol := SdlColor {byte(3), byte(2), byte(1), byte(0)} 468 | tsurf := C.TTF_RenderText_Solid(g.font, text.str, tcol) 469 | ttext := C.SDL_CreateTextureFromSurface(g.sdl.renderer, tsurf) 470 | texw := 0 471 | texh := 0 472 | C.SDL_QueryTexture(ttext, 0, 0, &texw, &texh) 473 | dstrect := SdlRect { x, y, texw, texh } 474 | C.SDL_RenderCopy(g.sdl.renderer, ttext, 0, &dstrect) 475 | C.SDL_DestroyTexture(ttext) 476 | vsdl2.free_surface(tsurf) 477 | } 478 | 479 | fn (g &Game) draw_score() { 480 | if g.font != voidptr(0) { 481 | g.draw_text(1, 2, 'score: ' + g.score.str() + ' nxt=' + g.tetro_next.str(), 0, 0, 0) 482 | if g.state == .gameover { 483 | g.draw_text(1, WinHeight / 2 + 0 * TextSize, 'Game Over', 0, 0, 0) 484 | g.draw_text(1, WinHeight / 2 + 2 * TextSize, 'SPACE to restart', 0, 0, 0) 485 | } else if g.state == .paused { 486 | g.draw_text(1, WinHeight / 2 + 0 * TextSize, 'Game Paused', 0, 0, 0) 487 | g.draw_text(1, WinHeight / 2 + 2 * TextSize, 'SPACE to resume', 0, 0, 0) 488 | } 489 | } 490 | } 491 | 492 | fn parse_binary_tetro(t_ int) []Block { 493 | mut t := t_ 494 | res := [Block{}].repeat(4) 495 | mut cnt := 0 496 | horizontal := t == 9// special case for the horizontal line 497 | for i := 0; i <= 3; i++ { 498 | // Get ith digit of t 499 | p := int(math.pow(10, 3 - i)) 500 | mut digit := int(t / p) 501 | t %= p 502 | // Convert the digit to binary 503 | for j := 3; j >= 0; j-- { 504 | bin := digit % 2 505 | digit /= 2 506 | if bin == 1 || (horizontal && i == TetroSize - 1) { 507 | // TODO: res[cnt].x = j 508 | // res[cnt].y = i 509 | mut point := &res[cnt] 510 | point.x = j 511 | point.y = i 512 | cnt++ 513 | } 514 | } 515 | } 516 | return res 517 | } 518 | -------------------------------------------------------------------------------- /tex2glad.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | const unsigned int SCR_WIDTH = 800, SCR_HEIGHT = 600; 6 | const char *vertexShaderSource = "#version 330 core\n" 7 | "layout (location = 0) in vec3 aPos;\n" 8 | "layout (location = 1) in vec3 aColor;\n" 9 | "out vec3 ourColor;\n" 10 | "uniform vec3 aOfs;\n" 11 | "void main(){\n" 12 | // " gl_Position = vec4(aOfs.x + aPos.x, -aPos.y, aPos.z, 1.0);\n" 13 | " gl_Position = vec4(aPos.x, -aPos.y, aPos.z, 1.0);\n" 14 | " ourColor = aColor + aOfs;\n" 15 | // " ourColor = aPos;\n" 16 | "}"; 17 | const char *fragmentShaderSource = "#version 330 core\n" 18 | "out vec4 FragColor;\n" 19 | "in vec3 ourColor;\n" 20 | "void main(){\n" 21 | " FragColor = vec4(ourColor, 1.0f);\n" 22 | "}"; 23 | void framebuffer_size_callback(GLFWwindow* window, int width, int height){ 24 | printf("window=%p\n", window); 25 | glViewport(0, 0, width, height); 26 | } 27 | int main(){ 28 | glfwInit(); 29 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 30 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 31 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 32 | GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); 33 | if (window == NULL){ 34 | std::cout << "Failed to create GLFW window" << std::endl; 35 | glfwTerminate(); 36 | return -1; 37 | } 38 | glfwMakeContextCurrent(window); 39 | glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); 40 | if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){ 41 | std::cout << "Failed to initialize GLAD" << std::endl; 42 | return -1; 43 | } 44 | int vertexShader = glCreateShader(GL_VERTEX_SHADER); 45 | glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); 46 | glCompileShader(vertexShader); 47 | int success; 48 | char infoLog[512]; 49 | glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); 50 | if (!success){ 51 | glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); 52 | std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; 53 | } 54 | int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 55 | glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); 56 | glCompileShader(fragmentShader); 57 | glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); 58 | if (!success){ 59 | glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); 60 | std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; 61 | } 62 | int shaderProgram = glCreateProgram(); 63 | glAttachShader(shaderProgram, vertexShader); 64 | glAttachShader(shaderProgram, fragmentShader); 65 | glLinkProgram(shaderProgram); 66 | glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); 67 | if (!success) { 68 | glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); 69 | std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; 70 | } 71 | glDeleteShader(vertexShader); 72 | glDeleteShader(fragmentShader); 73 | float vertices[] = { 74 | // positions // colors 75 | -0.5f, -0.5f, 0.0f, 1.0, 0.0, 0.0, // left 76 | 0.5f, -0.5f, 0.0f, 0.0, 1.0, 0.0, // right 77 | 0.0f, 0.5f, 0.0f, 0.0, 0.0, 1.0, // top 78 | }; 79 | unsigned int VBO, VAO; 80 | glGenVertexArrays(1, &VAO); 81 | glGenBuffers(1, &VBO); 82 | // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). 83 | glBindVertexArray(VAO); 84 | glBindBuffer(GL_ARRAY_BUFFER, VBO); 85 | glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 86 | // position 87 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); 88 | glEnableVertexAttribArray(0); 89 | // position 90 | glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))); 91 | glEnableVertexAttribArray(1); 92 | // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind 93 | glBindBuffer(GL_ARRAY_BUFFER, 0); 94 | // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other 95 | // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary. 96 | glBindVertexArray(0); 97 | int wireframe = 0; 98 | while (!glfwWindowShouldClose(window)){ 99 | glfwPollEvents(); 100 | if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) 101 | glfwSetWindowShouldClose(window, true); 102 | if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) 103 | wireframe = 1 - wireframe; 104 | glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL); 105 | // render 106 | glClearColor(0.2f, 0.3f, 0.3f, 1.0f); 107 | glClear(GL_COLOR_BUFFER_BIT); 108 | // draw our first triangle 109 | float timeValue = glfwGetTime(); 110 | float xOfs = (sin(timeValue) / 2.0f); 111 | int vertexColorLocation = glGetUniformLocation(shaderProgram, "aOfs"); 112 | glUniform3f(vertexColorLocation, xOfs, 0.0f, 0.0f); 113 | glUseProgram(shaderProgram); 114 | glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized 115 | glDrawArrays(GL_TRIANGLES, 0, 3); 116 | // glBindVertexArray(0); // no need to unbind it every time 117 | glfwSwapBuffers(window); 118 | } 119 | glDeleteVertexArrays(1, &VAO); 120 | glDeleteBuffers(1, &VBO); 121 | glfwTerminate(); 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /tex3glad.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #define STB_IMAGE_IMPLEMENTATION 6 | #include "stb_image.h" 7 | const unsigned int SCR_WIDTH = 800, SCR_HEIGHT = 600; 8 | const char *vertexShaderSource = "#version 330 core\n" 9 | "layout (location = 0) in vec3 aPos;\n" 10 | "layout (location = 1) in vec3 aColor;\n" 11 | "layout (location = 2) in vec2 aTexCoord;\n" 12 | "out vec3 ourColor;\n" 13 | "out vec2 TexCoord;\n" 14 | "uniform vec3 aOfs;\n" 15 | "void main(){\n" 16 | " gl_Position = vec4(aOfs.x + aPos.x, -aPos.y, aPos.z, 1.0);\n" 17 | // " gl_Position = vec4(aPos.x, -aPos.y, aPos.z, 1.0);\n" 18 | " ourColor = aColor + aOfs;\n" 19 | // " ourColor = aPos;\n" 20 | " TexCoord = aTexCoord;\n" 21 | "}"; 22 | const char *fragmentShaderSource = "#version 330 core\n" 23 | "out vec4 FragColor;\n" 24 | "in vec3 ourColor;\n" 25 | "in vec2 TexCoord;\n" 26 | "uniform sampler2D ourTexture;\n" 27 | "void main(){\n" 28 | // " FragColor = vec4(ourColor, 1.0f);\n" 29 | // " FragColor = texture(ourTexture, TexCoord);\n" 30 | " FragColor = texture(ourTexture, TexCoord) * vec4(ourColor, 1.0);\n" 31 | "}"; 32 | static void *g_p = 0; 33 | void framebuffer_size_callback(GLFWwindow* window, int width, int height){ 34 | // printf("window=%p\n", window); 35 | g_p = window; 36 | glViewport(0, 0, width, height); 37 | } 38 | int main(){ 39 | glfwInit(); 40 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 41 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 42 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 43 | GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); 44 | if (window == NULL){ 45 | std::cout << "Failed to create GLFW window" << std::endl; 46 | glfwTerminate(); 47 | return -1; 48 | } 49 | glfwMakeContextCurrent(window); 50 | glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); 51 | if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){ 52 | std::cout << "Failed to initialize GLAD" << std::endl; 53 | return -1; 54 | } 55 | int vertexShader = glCreateShader(GL_VERTEX_SHADER); 56 | glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); 57 | glCompileShader(vertexShader); 58 | int success; 59 | char infoLog[512]; 60 | glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); 61 | if (!success){ 62 | glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); 63 | std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; 64 | } 65 | int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 66 | glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); 67 | glCompileShader(fragmentShader); 68 | glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); 69 | if (!success){ 70 | glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); 71 | std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; 72 | } 73 | int shaderProgram = glCreateProgram(); 74 | glAttachShader(shaderProgram, vertexShader); 75 | glAttachShader(shaderProgram, fragmentShader); 76 | glLinkProgram(shaderProgram); 77 | glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); 78 | if (!success) { 79 | glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); 80 | std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; 81 | } 82 | glDeleteShader(vertexShader); 83 | glDeleteShader(fragmentShader); 84 | float vertices[] = { 85 | // positions // colors // tex coords 86 | -0.5f, -0.5f, 0.0f, 1.0, 0.0, 0.0, 0.0, 0.0, // left 87 | 0.5f, -0.5f, 0.0f, 0.0, 1.0, 0.0, 1.0, 0.0, // right 88 | 0.0f, 0.5f, 0.0f, 0.0, 0.0, 1.0, 0.5, 1.0, // top 89 | }; 90 | unsigned int VBO, VAO; 91 | glGenVertexArrays(1, &VAO); 92 | glGenBuffers(1, &VBO); 93 | // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). 94 | glBindVertexArray(VAO); 95 | glBindBuffer(GL_ARRAY_BUFFER, VBO); 96 | glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 97 | // positions 98 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); 99 | glEnableVertexAttribArray(0); 100 | // colors 101 | glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); 102 | glEnableVertexAttribArray(1); 103 | // tex coords 104 | glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); 105 | glEnableVertexAttribArray(2); 106 | // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind 107 | glBindBuffer(GL_ARRAY_BUFFER, 0); 108 | // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other 109 | // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary. 110 | glBindVertexArray(0); 111 | unsigned int texture; 112 | glGenTextures(1, &texture); 113 | glBindTexture(GL_TEXTURE_2D, texture); 114 | // set the texture wrapping/filtering options (on the currently bound texture object) 115 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 116 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 117 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 118 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 119 | // load and generate the texture 120 | int width, height, nrChannels; 121 | unsigned char *data = stbi_load("textures/wall.jpg", &width, &height, &nrChannels, 0); 122 | if (data) 123 | { 124 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); 125 | glGenerateMipmap(GL_TEXTURE_2D); 126 | } 127 | else 128 | { 129 | std::cout << "Failed to load texture" << std::endl; 130 | } 131 | stbi_image_free(data); 132 | 133 | int wireframe = 0; 134 | while (!glfwWindowShouldClose(window)){ 135 | glfwPollEvents(); 136 | if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) 137 | glfwSetWindowShouldClose(window, true); 138 | if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) 139 | wireframe = 1 - wireframe; 140 | glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL); 141 | // render 142 | glClearColor(0.2f, 0.3f, 0.3f, 1.0f); 143 | glClear(GL_COLOR_BUFFER_BIT); 144 | // draw our first triangle 145 | float timeValue = glfwGetTime(); 146 | float xOfs = (sin(timeValue) / 2.0f); 147 | int vertexColorLocation = glGetUniformLocation(shaderProgram, "aOfs"); 148 | glUniform3f(vertexColorLocation, xOfs, 0.0f, 0.0f); 149 | glUseProgram(shaderProgram); 150 | glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized 151 | glDrawArrays(GL_TRIANGLES, 0, 3); 152 | // glBindVertexArray(0); // no need to unbind it every time 153 | glfwSwapBuffers(window); 154 | } 155 | glDeleteVertexArrays(1, &VAO); 156 | glDeleteBuffers(1, &VBO); 157 | glfwTerminate(); 158 | return 0; 159 | } 160 | -------------------------------------------------------------------------------- /tex4glad.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #define STB_IMAGE_IMPLEMENTATION 7 | #include "stb_image.h" 8 | const unsigned int SCR_WIDTH = 800, SCR_HEIGHT = 600; 9 | const char *vertexShaderSource = "#version 330 core\n" 10 | "layout (location = 0) in vec3 aPos;\n" 11 | "layout (location = 1) in vec3 aColor;\n" 12 | "layout (location = 2) in vec2 aTexCoord;\n" 13 | "out vec3 ourColor;\n" 14 | "out vec2 TexCoord;\n" 15 | "uniform vec3 aOfs;\n" 16 | "void main(){\n" 17 | " gl_Position = vec4(aOfs.x + aPos.x, -aPos.y, aPos.z, 1.0);\n" 18 | // " gl_Position = vec4(aPos.x, -aPos.y, aPos.z, 1.0);\n" 19 | " ourColor = aColor + aOfs;\n" 20 | // " ourColor = aPos;\n" 21 | " TexCoord = aTexCoord;\n" 22 | "}"; 23 | const char *fragmentShaderSource = "#version 330 core\n" 24 | "out vec4 FragColor;\n" 25 | "in vec3 ourColor;\n" 26 | "in vec2 TexCoord;\n" 27 | "uniform sampler2D ourTexture;\n" 28 | "void main(){\n" 29 | // " FragColor = vec4(ourColor, 1.0f);\n" 30 | " FragColor = texture(ourTexture, TexCoord);\n" 31 | // " FragColor = texture(ourTexture, TexCoord) * vec4(ourColor, 1.0);\n" 32 | "}"; 33 | static void *g_p = 0; 34 | void framebuffer_size_callback(GLFWwindow* window, int width, int height){ 35 | // printf("window=%p\n", window); 36 | g_p = window; 37 | glViewport(0, 0, width, height); 38 | } 39 | int main(){ 40 | glfwInit(); 41 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 42 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 43 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 44 | GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); 45 | if (window == NULL){ 46 | std::cout << "Failed to create GLFW window" << std::endl; 47 | glfwTerminate(); 48 | return -1; 49 | } 50 | glfwMakeContextCurrent(window); 51 | glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); 52 | if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){ 53 | std::cout << "Failed to initialize GLAD" << std::endl; 54 | return -1; 55 | } 56 | int vertexShader = glCreateShader(GL_VERTEX_SHADER); 57 | glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); 58 | glCompileShader(vertexShader); 59 | int success; 60 | char infoLog[512]; 61 | glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); 62 | if (!success){ 63 | glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); 64 | std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; 65 | } 66 | int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 67 | glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); 68 | glCompileShader(fragmentShader); 69 | glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); 70 | if (!success){ 71 | glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); 72 | std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; 73 | } 74 | int shaderProgram = glCreateProgram(); 75 | glAttachShader(shaderProgram, vertexShader); 76 | glAttachShader(shaderProgram, fragmentShader); 77 | glLinkProgram(shaderProgram); 78 | glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); 79 | if (!success) { 80 | glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); 81 | std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; 82 | } 83 | glDeleteShader(vertexShader); 84 | glDeleteShader(fragmentShader); 85 | float vertices[] = { 86 | // positions // colors // texture coords 87 | 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right 88 | 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right 89 | -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left 90 | -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left 91 | }; 92 | unsigned int indices[] = { 93 | 0, 1, 3, // first triangle 94 | 1, 2, 3 // second triangle 95 | }; 96 | unsigned int VBO, VAO, EBO; 97 | glGenVertexArrays(1, &VAO); 98 | glGenBuffers(1, &VBO); 99 | glGenBuffers(1, &EBO); 100 | // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). 101 | glBindVertexArray(VAO); 102 | glBindBuffer(GL_ARRAY_BUFFER, VBO); 103 | glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 104 | 105 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); 106 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); 107 | 108 | // positions 109 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); 110 | glEnableVertexAttribArray(0); 111 | // colors 112 | glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); 113 | glEnableVertexAttribArray(1); 114 | // tex coords 115 | glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); 116 | glEnableVertexAttribArray(2); 117 | // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind 118 | glBindBuffer(GL_ARRAY_BUFFER, 0); 119 | // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other 120 | // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary. 121 | glBindVertexArray(0); 122 | unsigned int texture; 123 | glGenTextures(1, &texture); 124 | glBindTexture(GL_TEXTURE_2D, texture); 125 | // set the texture wrapping/filtering options (on the currently bound texture object) 126 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 127 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 128 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 129 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 130 | // load and generate the texture 131 | int width, height, nrChannels; 132 | unsigned char *data = 0; 133 | #if 0 134 | data = stbi_load("textures/wall.jpg", &width, &height, &nrChannels, 0); 135 | #else 136 | width = SCR_WIDTH; 137 | height = SCR_HEIGHT; 138 | nrChannels = 4; 139 | data = (unsigned char *)calloc(width * height, nrChannels); 140 | #endif 141 | if (data) 142 | { 143 | printf("channels=%d\n", (int)nrChannels); 144 | // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); 145 | // glGenerateMipmap(GL_TEXTURE_2D); 146 | } 147 | else 148 | { 149 | std::cout << "Failed to load texture" << std::endl; 150 | } 151 | 152 | #if 1 153 | char col = 0; 154 | for (int j = 0; j < height; j++) { 155 | if (!(j % 10)) 156 | col = 255 - col; 157 | for (int i = 0; i < width; i++) { 158 | if (!(i % 10)) 159 | col = 255 - col; 160 | data[j * width * nrChannels + i * nrChannels + 0] = col; 161 | data[j * width * nrChannels + i * nrChannels + 1] = 0; 162 | data[j * width * nrChannels + i * nrChannels + 2] = 0; 163 | if ((i < width / 3) || (i > 2 * width / 3)) 164 | data[j * width * nrChannels + i * nrChannels + 3] = 255; 165 | } 166 | } 167 | #endif 168 | int wireframe = 0; 169 | while (!glfwWindowShouldClose(window)){ 170 | glfwPollEvents(); 171 | if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) 172 | glfwSetWindowShouldClose(window, true); 173 | if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) 174 | wireframe = 1 - wireframe; 175 | glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL); 176 | // render 177 | glClearColor(0.2f, 0.3f, 0.3f, 1.0f); 178 | glClear(GL_COLOR_BUFFER_BIT); 179 | // draw our first quad 180 | glEnable(GL_BLEND); 181 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 182 | 183 | float timeValue = glfwGetTime(); 184 | float xOfs = (sin(timeValue) / 1.9f); 185 | int vertexColorLocation = glGetUniformLocation(shaderProgram, "aOfs"); 186 | glUniform3f(vertexColorLocation, xOfs, 0.0f, 0.0f); 187 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); 188 | 189 | glBindTexture(GL_TEXTURE_2D, texture); 190 | glUseProgram(shaderProgram); 191 | glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized 192 | glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); 193 | // glBindVertexArray(0); // no need to unbind it every time 194 | glfwSwapBuffers(window); 195 | usleep(50000); 196 | } 197 | glDeleteVertexArrays(1, &VAO); 198 | glDeleteBuffers(1, &VBO); 199 | glDeleteBuffers(1, &EBO); 200 | glfwTerminate(); 201 | if (data) { 202 | stbi_image_free(data); 203 | } 204 | return 0; 205 | } 206 | -------------------------------------------------------------------------------- /texglad.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | const unsigned int SCR_WIDTH = 800, SCR_HEIGHT = 600; 7 | const char *vertexShaderSource = "#version 330 core\n" 8 | "layout (location = 0) in vec3 aPos;\n" 9 | "out vec4 ourColor;\n" 10 | "void main(){\n" 11 | " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" 12 | " ourColor = vec4(0.0f, 0.0f, 1.0f, 1.0f);\n" 13 | "}"; 14 | const char *fragmentShaderSource = "#version 330 core\n" 15 | "out vec4 FragColor;\n" 16 | // "in vec4 ourColor;\n" 17 | "uniform vec4 ourColor;\n" 18 | "void main(){\n" 19 | // " FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" 20 | " FragColor = ourColor;\n" 21 | "}"; 22 | 23 | void framebuffer_size_callback(GLFWwindow* window, int width, int height){ 24 | printf("window=%p\n", window); 25 | glViewport(0, 0, width, height); 26 | } 27 | int main(){ 28 | glfwInit(); 29 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 30 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 31 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 32 | GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); 33 | if (window == NULL){ 34 | std::cout << "Failed to create GLFW window" << std::endl; 35 | glfwTerminate(); 36 | return -1; 37 | } 38 | glfwMakeContextCurrent(window); 39 | glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); 40 | if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){ 41 | std::cout << "Failed to initialize GLAD" << std::endl; 42 | return -1; 43 | } 44 | int vertexShader = glCreateShader(GL_VERTEX_SHADER); 45 | glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); 46 | glCompileShader(vertexShader); 47 | int success; 48 | char infoLog[512]; 49 | glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); 50 | if (!success){ 51 | glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); 52 | std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; 53 | } 54 | int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 55 | glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); 56 | glCompileShader(fragmentShader); 57 | glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); 58 | if (!success){ 59 | glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); 60 | std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; 61 | } 62 | 63 | int shaderProgram = glCreateProgram(); 64 | glAttachShader(shaderProgram, vertexShader); 65 | glAttachShader(shaderProgram, fragmentShader); 66 | glLinkProgram(shaderProgram); 67 | glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); 68 | if (!success) { 69 | glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); 70 | std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; 71 | } 72 | glDeleteShader(vertexShader); 73 | glDeleteShader(fragmentShader); 74 | 75 | float vertices[] = { 76 | -0.5f, -0.5f, 0.0f, // left 77 | 0.5f, -0.5f, 0.0f, // right 78 | 0.0f, 0.5f, 0.0f // top 79 | }; 80 | unsigned int VBO, VAO; 81 | glGenVertexArrays(1, &VAO); 82 | glGenBuffers(1, &VBO); 83 | // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). 84 | glBindVertexArray(VAO); 85 | 86 | glBindBuffer(GL_ARRAY_BUFFER, VBO); 87 | glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 88 | 89 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); 90 | glEnableVertexAttribArray(0); 91 | 92 | // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind 93 | glBindBuffer(GL_ARRAY_BUFFER, 0); 94 | 95 | // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other 96 | // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary. 97 | glBindVertexArray(0); 98 | 99 | int wireframe = 0; 100 | while (!glfwWindowShouldClose(window)){ 101 | glfwPollEvents(); 102 | if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) 103 | glfwSetWindowShouldClose(window, true); 104 | if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) 105 | wireframe = 1 - wireframe; 106 | glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL); 107 | 108 | // render 109 | // ------ 110 | glClearColor(0.2f, 0.3f, 0.3f, 1.0f); 111 | glClear(GL_COLOR_BUFFER_BIT); 112 | 113 | // draw our first triangle 114 | float timeValue = glfwGetTime(); 115 | float greenValue = (sin(timeValue) / 2.0f) + 0.5f; 116 | int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor"); 117 | glUseProgram(shaderProgram); 118 | glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f); 119 | glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized 120 | glDrawArrays(GL_TRIANGLES, 0, 3); 121 | // glBindVertexArray(0); // no need to unbind it every time 122 | glfwSwapBuffers(window); 123 | } 124 | glDeleteVertexArrays(1, &VAO); 125 | glDeleteBuffers(1, &VBO); 126 | glfwTerminate(); 127 | return 0; 128 | } 129 | -------------------------------------------------------------------------------- /textures/wall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/textures/wall.jpg -------------------------------------------------------------------------------- /tvintris.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/tvintris.png -------------------------------------------------------------------------------- /tvintrisgl.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/tvintrisgl.gif -------------------------------------------------------------------------------- /tvintrisgl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/tvintrisgl.png -------------------------------------------------------------------------------- /vig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/vig.png -------------------------------------------------------------------------------- /vnk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/vnk.png -------------------------------------------------------------------------------- /vsdl/vsdl.v: -------------------------------------------------------------------------------- 1 | // Copyright(C) 2019 Nicolas Sauzede. All rights reserved. 2 | // Use of this source code is governed by an MIT license 3 | // that can be found in the LICENSE_v.txt file. 4 | 5 | module vsdl 6 | 7 | #flag linux `sdl2-config --cflags --libs` -lSDL2_ttf -lSDL2_mixer 8 | #include 9 | #include 10 | #include 11 | 12 | //fn C.SDL_Init(flags u32) int 13 | //fn C.SDL_CreateWindowAndRenderer(w int, h int, flags u32, window voidptr, renderer voidptr) int 14 | fn C.SDL_CreateRGBSurface(flags u32, width int, height int, depth int, Rmask u32, Gmask u32, Bmask u32, Amask u32) &SdlSurface 15 | //fn C.SDL_CreateTexture(renderer voidptr, format u32, access int, w int, h int) voidptr 16 | //fn C.SDL_MapRGB(format voidptr, r byte, g byte, b byte) u32 17 | //fn C.SDL_PollEvent(voidptr) int 18 | //fn C.stubTTF_RenderText_Solid(font voidptr, text voidptr, col *SdlColor, ret **SdlSurface) 19 | 20 | //fn C.stubTTF_RenderText_Solid(font voidptr, text voidptr, col &SdlColor, ret &voidptr) 21 | 22 | //fn C.TTF_Quit() 23 | //fn C.TTF_OpenFont(a byteptr, b int) voidptr 24 | //type SdlColor struct 25 | 26 | //struct C.TTF_Font { } 27 | 28 | struct C.SDL_Color{ 29 | pub: 30 | r byte 31 | g byte 32 | b byte 33 | a byte 34 | } 35 | type SdlColor C.SDL_Color 36 | 37 | struct C.SDL_Rect { 38 | pub: 39 | x int 40 | y int 41 | w int 42 | h int 43 | } 44 | type SdlRect C.SDL_Rect 45 | 46 | //type SdlScancode int // TODO define the real enum here 47 | //type SdlKeycode int 48 | //type SdlRect SdlRect 49 | //type SdlColor C.SDL_Color 50 | //type SdlSurface SdlSurface 51 | //type MixChunk C.Mix_Chunk 52 | 53 | struct SdlQuitEvent { 54 | _type u32 55 | timestamp u32 56 | } 57 | struct SdlKeysym { 58 | pub: 59 | // scancode SdlScancode 60 | scancode int 61 | // sym SdlKeycode 62 | sym int 63 | mod u16 64 | unused u32 65 | } 66 | struct SdlKeyboardEvent { 67 | pub: 68 | _type u32 69 | timestamp u32 70 | windowid u32 71 | state byte 72 | repeat byte 73 | padding2 byte 74 | padding3 byte 75 | keysym SdlKeysym 76 | } 77 | struct SdlJoyButtonEvent { 78 | pub: 79 | _type u32 80 | timestamp u32 81 | which int 82 | button byte 83 | state byte 84 | } 85 | struct SdlJoyHatEvent { 86 | pub: 87 | _type u32 88 | timestamp u32 89 | which int 90 | hat byte 91 | value byte 92 | } 93 | union SdlEventU { 94 | pub: 95 | _type u32 96 | quit SdlQuitEvent 97 | key SdlKeyboardEvent 98 | jbutton SdlJoyButtonEvent 99 | jhat SdlJoyHatEvent 100 | } 101 | type SdlEvent SdlEventU 102 | 103 | struct C.SDL_Surface { 104 | pub: 105 | flags u32 106 | format voidptr 107 | w int 108 | h int 109 | pitch int 110 | pixels voidptr 111 | userdata voidptr 112 | locked int 113 | lock_data voidptr 114 | clip_rect SdlRect 115 | map voidptr 116 | refcount int 117 | } 118 | type SdlSurface C.SDL_Surface 119 | 120 | //type SdlAudioFormat u16 121 | //type SdlAudioCallback_t fn(userdata voidptr, stream &byte, len int) 122 | //struct SdlAudioSpec { 123 | struct C.SDL_AudioSpec { 124 | pub: 125 | mut: 126 | freq int 127 | // format SdlAudioFormat 128 | format u16 129 | channels byte 130 | silence byte 131 | samples u16 132 | size u32 133 | // callback SdlAudioCallback_t 134 | callback voidptr 135 | userdata voidptr 136 | } 137 | type SdlAudioSpec C.SDL_AudioSpec 138 | 139 | 140 | const ( 141 | version = '0.0.1' 142 | ) 143 | -------------------------------------------------------------------------------- /vsdl/vsdlstub.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define dbgprintf(...) do{}while(0) 5 | 6 | /* 7 | This dumb C STUB is to work around the fact V transpiler fails 8 | when function arguments like struct are passed by value, 9 | and also fails to allow returning a 64 bits void pointer. 10 | */ 11 | 12 | // obsolete 13 | // use this V instead : 14 | // text string, tcol SdlColor 15 | // tsurf := C.TTF_RenderText_Solid(g.font, text.str, tcol) 16 | #if 0 17 | 18 | #include 19 | 20 | DECLSPEC void SDLCALL stubTTF_RenderText_Solid(TTF_Font *font, 21 | const char *text, SDL_Color *fg, SDL_Surface **ret) { 22 | /* 23 | SDL_Color _fg = {0, 0, 0, 0}; 24 | fg = &_fg; 25 | */ 26 | dbgprintf("%s: got font=%p text=%p (%s) fg=%p ret=%p (%p)\n", __func__, font, text, text, fg, ret, *ret); 27 | dbgprintf("%s: got color=%"PRIu8",%"PRIu8",%"PRIu8",%"PRIu8"\n", __func__, fg->r, fg->g, fg->b, fg->a); 28 | SDL_Surface *res = TTF_RenderText_Solid(font, text, *fg); 29 | dbgprintf("%s: returning res=%p\n", __func__, res); 30 | *ret = res; 31 | } 32 | 33 | #endif 34 | 35 | // obsolete -- use this V myrand_r until V rand_r is available 36 | // Ported from https://git.musl-libc.org/cgit/musl/diff/src/prng/rand_r.c?id=0b44a0315b47dd8eced9f3b7f31580cf14bbfc01 37 | // Thanks spytheman 38 | //fn myrand_r(seed &int) int { 39 | // mut rs := seed 40 | // ns := ( *rs * 1103515245 + 12345 ) 41 | // *rs = ns 42 | // return ns & 0x7fffffff 43 | //} 44 | #if 0 45 | 46 | #ifdef WIN32 47 | int rand_r(unsigned int *seedp) { 48 | srand(*seedp); 49 | *seedp = rand(); 50 | return *seedp; 51 | } 52 | #endif 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /vsdl2gl/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Nicolas Sauzede 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vsdl2gl/README.md: -------------------------------------------------------------------------------- 1 | # vsdlgl 2 | SDL2 V module -- libSDL2 wrapper 3 | 4 | Current APIs available/tested in examples : 5 | - basic graphics (2D drawing) 6 | - TTF font (text rendering) 7 | - input handling (keyboard/joystick events) 8 | - sounds (WAV mixing) 9 | - music (MOD mixing) 10 | - more to come.. (networking ?) 11 | 12 | # Examples 13 | 14 | [tVintris](https://github.com/nsauzede/vsdl2/tree/master/examples/tvintris) 15 | 16 | ![tVintris screenshot](https://github.com/nsauzede/vsdl2/blob/master/examples/tvintris/tvintris.png) 17 | 18 | # Dependencies 19 | Ubuntu : 20 | `$ sudo apt install libsdl2-ttf-dev libsdl2-mixer-dev` 21 | 22 | ClearLinux : 23 | `$ sudo swupd bundle-add devpkg-SDL2_ttf devpkg-SDL2_mixer` 24 | 25 | Windows/MSYS2 : 26 | `$ pacman -S mingw-w64-x86_64-SDL2_ttf mingw-w64-x86_64-SDL2_mixer` 27 | -------------------------------------------------------------------------------- /vsdl2gl/examples/tvintris/README.md: -------------------------------------------------------------------------------- 1 | # tVintris 2 | 3 | tvintris.v is a dual-player (local) version based on original source from vlang/v example by Alex M. 4 | It is largely inspired by ancient game Twintris. 5 | -uses published vpm module nsauzede.vsdl2 6 | 7 | 8 | 9 | Colors, Music and Sounds ripped from amiga title Twintris (1990 nostalgia !) 10 | - Graphician : Svein Berge 11 | - Musician : Tor Bernhard Gausen (Walkman/Cryptoburners) 12 | 13 | # how to run tVintris 14 | 15 | `$ v install nsauzede.vsdl2` 16 | `$ v run .` 17 | -------------------------------------------------------------------------------- /vsdl2gl/examples/tvintris/fonts/RobotoMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/vsdl2gl/examples/tvintris/fonts/RobotoMono-Regular.ttf -------------------------------------------------------------------------------- /vsdl2gl/examples/tvintris/sounds/TwintrisThosenine.mod: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/vsdl2gl/examples/tvintris/sounds/TwintrisThosenine.mod -------------------------------------------------------------------------------- /vsdl2gl/examples/tvintris/sounds/block.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/vsdl2gl/examples/tvintris/sounds/block.wav -------------------------------------------------------------------------------- /vsdl2gl/examples/tvintris/sounds/single.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/vsdl2gl/examples/tvintris/sounds/single.wav -------------------------------------------------------------------------------- /vsdl2gl/examples/tvintris/sounds/triple.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/vsdl2gl/examples/tvintris/sounds/triple.wav -------------------------------------------------------------------------------- /vsdl2gl/examples/tvintris/tvintris.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsauzede/sdl2test/88d4a4efa51509427d4c4e0e7d172fa56f72f743/vsdl2gl/examples/tvintris/tvintris.png -------------------------------------------------------------------------------- /vsdl2gl/v.mod: -------------------------------------------------------------------------------- 1 | Module { 2 | name: 'vsdl2gl' 3 | version: '0.0.1' 4 | deps: ['vsdl2'] 5 | } 6 | -------------------------------------------------------------------------------- /vsdl2gl/vsdl2gl.v: -------------------------------------------------------------------------------- 1 | // Copyright(C) 2019 Nicolas Sauzede. All rights reserved. 2 | // Use of this source code is governed by an MIT license 3 | // that can be found in the LICENSE file. 4 | 5 | module vsdl2gl 6 | 7 | import nsauzede.vsdl2 8 | 9 | // apparently, following line also works on non-linux ? o_O 10 | #flag linux -lGL -lGLU 11 | #include 12 | #include 13 | 14 | pub fn fill_rect(screen &vsdl2.Surface, rect &vsdl2.Rect, col &vsdl2.Color) { 15 | ww := screen.w 16 | hh := screen.h 17 | r := f32(col.r) / 255 18 | g := f32(col.g) / 255 19 | b := f32(col.b) / 255 20 | x := f32(2) * rect.x / (ww - 1) - 1 21 | y := f32(2) * ((hh - 1) - rect.y) / (hh - 1) - 1 22 | w := f32(2) * rect.w / ww 23 | h := f32(2) * rect.h / hh 24 | C.glMatrixMode(C.GL_MODELVIEW) 25 | C.glLoadIdentity() 26 | C.glBegin(C.GL_QUADS) 27 | C.glColor3f(r, g, b) 28 | C.glVertex2f(x, y) 29 | C.glVertex2f(x + w, y) 30 | C.glVertex2f(x + w, y - h) 31 | C.glVertex2f(x, y - h) 32 | C.glEnd() 33 | } 34 | --------------------------------------------------------------------------------