Building SDL project with .bat-file

I have become a huge fan of Casey's .bat-file building during this project and now I'm trying to use that on my other projects.

Currently I'm trying to build a project that is using a SDL library (only including SDL.h). However, I cannot get it to work. Currently my .bat-file looks like this:

1
2
3
4
5
@echo off
mkdir ..\build
pushd ..\build
cl -Zi ..\code\win32_ascii.cpp SDL.lib SDLmain.lib
popd


Cl compiler is giving me an error:
1
LINK : fatal error LNK1561: entry point must be defined


The program I'm using to test this is just a simple example from the SDL documentation:

1
2
3
4
5
6
7
#include "SDL/SDL.h"
int main(int argc, char* args[])
{
   SDL_Init( SDL_INIT_EVERYTHING );
   SDL_Quit();
   return 0;
}


Currently I have those .lib-files in the same directory than the .bat-file but I don't know if I actually need something else from the downloaded SDL package as well.
Is it SDL.lib SDLmain.lib or SDL2.lib SDL2main.lib?
Have you tried to set the /SUBSYSTEM for the linker to CONSOLE or WINDOWS?
Setting the SUBSYSTEM did not fix it alone but I got it working by changing main to wmain. Seems like it was compiling with unicode by default which apparently requires wmain.
Here's what worked for me:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
SETLOCAL

set TARGET=x86

:: SDL2 libraries and include paths 
set SDL2_LIB=..\SDL2-2.0.3
set SDL2_IMG=..\SDL2_image-2.0.0

set SDL2_LIBDIR=%SDL2_LIB%\lib\%TARGET%
set SDL2_IMGDIR=%SDL2_IMG%\lib\%TARGET%
set SDL2_LIBINC=%SDL2_LIB%\include
set SDL2_IMGINC=%SDL2_IMG%\include

pushd ..\..\..\..\build

call "D:\Beer\Program Files (x86)\Microsoft Visual Studio 12.0\VC\Vcvarsall.bat" %TARGET%

robocopy %SDL2_LIBDIR% . *.dll
robocopy %SDL2_IMGDIR% . *.dll

cl -Zi -FC -MD ..\STG\SDL2\code\win32_STG.cpp -I%SDL2_LIBINC% -I%SDL2_IMGINC% %SDL2_LIBDIR%\SDL2.lib %SDL2_LIBDIR%\SDL2main.lib %SDL2_IMGDIR%\SDL2_image.lib -link /machine:%TARGET% -entry:WinMainCRTStartup -subsystem:WINDOWS
popd
Seeing this finally gave me reason to create a forum account!

So, I've also been using SDL2 to implement my 'platform-layer' atop windows,
mainly to get to use my gamepad wich does not use XInput and I couldn't be bothered with DirectInput.
Anyway, here's how I compile (x64!): (build.bat)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
@echo off
set Pincludes=x:\ext_libs\include
set Plibs=x:\ext_libs\lib\x64

set PDBLockPrevention=-PDB:handmade_%random%.pdb
set EXPORTS=-EXPORT:GameGetSoundSamples -EXPORT:GameUpdateAndRender

x:
if not defined DevEnvDir (
call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x64
)

set CommonCompilerFlags=-MD -nologo -Gm- -GR- -EHa- -Od -Oi -WX -W4 -wd4201 -wd4100 -wd4189 -wd4505 -FC -Z7 /I%Pincludes% -DHANDMADE_SLOW=1 -DHANDMADE_INTERNAL=1
set CommonLinkerFlags=/incremental:no /opt:ref /LIBPATH:%Plibs% SDL2.lib SDL2main.lib

pushd ..\build

del *.pdb > NUL 2> NUL
cl  %CommonCompilerFlags% ..\code\handmade.cpp -Fmair.map -LD /link /subsystem:windows,6.1 /incremental:no %PDBLockPrevention% %EXPORTS%
cl  %CommonCompilerFlags% ..\code\sdl_handmade.cpp -Fmsdl_handmade.map /link /subsystem:console %CommonLinkerFlags%

popd

Dir-layout is: (where x: is a subst to the full folder path)

x:\build -> stuff gets built here
x:\code -> code here
x:\ext_libs -> this is where SDL2 for VC goes (SDL2-devel-2.0.3-VC.zip)
\include -> SDL2 headers
\lib\x64 -> arch specific *.lib files
\lib\x86 -> "
Obviously you need to place a copy of SDL2.dll in the 'build' dir for your executable to use when run.
Note that I don't need to use the -entry flag and can have a normal 'int main(...)'.
The '/subsystem:console' is only there so that I could see 'printf()' output, which if wanted could also require 'User32.lib' on the 'commonLinkerFlags' line and the stdio.h include in the code!

Edited by Tom on
Interesting, I can tell you are further ahead in the series than I :)
Its basically from just past the win32-platform layer stuff, including the live loading stuff.
I'm at around episode 60, but the platform stuff hasn't changed for quite a while, but I'm sure it will again at some point, so I can't say if my approach still works with 'upstream', then again I'm quite sure it can be adapted.

The differences in my actual 'sdl-platform-code' as compared the sdl-port available on github (which is aimed at unix/linux) are all the memory related functions as well as filehandle-stuff, and for those I just used those from casey's code!
Hey guys, I'm considering using SDL as a 'better platform-layer' replacement of Windows's API as well. I wonder how well it maps to the things we do in HMH. For example, does it let you give it a raw audio buffer of bytes to play? same with framebuffer (software rendering in general)? In general, what is your experience with it and would you recommend it? how much overhead is there for using it?

Edited by vexe on
In SDL audio has pull model. Meaning - you specify callback which will be called by SDL at any time audio device needs more audio samples. https://wiki.libsdl.org/SDL_AudioSpec
This is very different from what HH uses (push model).

For framebuffer you can modify pixels by getting window surface. Surface contains pointer to memory you modify. When done with it, you can ask window to update modified data (present on screen). Relevant functions for accessing pixels for window:
https://wiki.libsdl.org/SDL_CreateWindow
https://wiki.libsdl.org/SDL_GetWindowSurface
https://wiki.libsdl.org/SDL_Surface
https://wiki.libsdl.org/SDL_UpdateWindowSurface
Or you can go OpenGL route that is used now in HH, then it works with exactly same code as in HH.

Other difference will be file access. SDL doesn't provide anything there. So you'll need to use either regular fopen, or do platform specifc stuff (or even use another library like physfs).

Other than that you should be able to do everything else without any issues. SDL is pretty nice.
Thanks for the reply mmozeiko!

SDL caught my eye because mainly because it seemed like a better platform-layer to rely upon. (Audio, Input, Video, creating windows and OpenGL context. While usually these things are segregated into different libraries, it's nice if they're all in one).

Regarding Audio, you mentioned the pull model. Could you elaborate more on how this plays with the current setup of HMH? i.e. If I use this model, will I also have a 'GameGetSoundSamples' function that I call in the game asking it to fill the sound output buffer? or will we have to employ a different technique now?

Edited by vexe on
Yes, you could call into game whenever SDL requires you to provide audio. The tricky part is choosing how often to do that (you do it only once with device open function). If you choose wrong value you'll get buffer underrun (glitches/cracks) or too big latency.

Probably better option would be to assume that SDL will need audio for at least next frame (+ something more to avoid underrun) and always mix temporary audio buffer in each frame for that. Then in callback function simply do memcpy and remember how much audio you've used. Then in next frame update you can restart audio mixing from the place you stopped passing data to SDL with memcpy.
Since the recent SDL 2.0.4 release, it seems (I haven't tested it yet) you can use the push model by not setting a callback function.

I've written a bare-bones SDL platform layer for my little project - in theory it will use the push method if SDL 2.0.4 is used, and the callback if something less is used - https://github.com/nxsy/hajonta/b.../source/hajonta/platform/sdl2.cpp
Thanks for the help guys!

I'm messing around with it, some references say I have to sandwich my pixel manipulation between calls to SDL_LockSurface and SDL_UnlockSurface, other references say it may not be necessary. But they never mention why. Does it hurt if I always lock/unlock just in case?

Another question, so I create a window via SDL_CreateWindow, and get its surface via SDL_GetWindowSurface, I look at the pixel format and it's 32-bits per pixel RGBA8888. I tried changing it via SDL_ConvertSurfaceFormat to RGB888 or RGB444 but it didn't seem to actually change it (looking at Surface->format values in the debugger), also tried initializing a SDL_PixelFormat struct and feeding that to SDL_ConvertSurface, same. Any idea why can't I change the pixel format?
Yes, you need to lock surface. It depends on surface implementation whether you actually need or not to do that. But in case you don't need to do that, LockSurface will simply be no operation, it won't do anything and will return immediately.

SDL_ConvertSurfaceFormat returns new surface with specified format and converted pixel values. It doesn't change format of existing surface.
Oops, should read the docs better next time :D

However they don't say what to do with the previous Surface. Should we destroy it?

With this code:
SDL_Surface *Surface = SDL_GetWindowSurface(Window);
Surface = SDL_ConvertSurfaceFormat(Surface, SDL_PIXELFORMAT_RGB888, 0);

Setting pixels in the framebuffer doesn't do anything (commenting out the second line I do see colors). I assume we shouldn't mess with the window surface but instead have another surface that we set the format and blit to? then copy over to screen surface or something?

Edited by vexe on