I am trying to render 3 things:
- geometric shapes (in this example a circle) using gfxPrimitives
- images/textures (optional)
- a GUI with AntTewakBar (compiled for SDL2 on OS X from here)
Each of those works fine by its own, but combining them somehow breaks the AntTweakBar, depending on the combination:
- Only AntTweakBar: renders everything fine

- AntTweakBar + Texture: everything but the text disappeared in the TestBar. The mouse is in the same position as before, but 'width' is not highlighted and all "icons" are missing. Somehow, the 'Help & Shortcuts'-bars background survived. Removing the texture again won't change anything. Adding the circle will lead to case 3

- AntTweakBar + Circle (+Texture):everything but the text gets rendered and the text turned into boxes. Adding the texture or removing the circle again won't change anything, but removing the circle first and then adding the texture will lead to case 2.

Here is the (messy) source code for this test application. res_path.h and cleanup.h can be found here and here (but should not matter).
#include <iostream>
#include <SDL2/SDL.h>
#include "res_path.h"
#include "cleanup.h"
#include "SDL2/SDL2_gfxPrimitives.h"
#include <AntTweakBar.h>
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
bool quit = false;
bool tex = false;
bool circ = false;
//-----------------------------------------------------------------------
/**
* Log an SDL error with some error message to the output stream of our choice
* @param os The output stream to write the message to
* @param msg The error message to write, format will be msg error: SDL_GetError()
*/
void logSDLError(std::ostream &os, const std::string &msg)
{
os << msg << " error: " << SDL_GetError() << std::endl;
}
/**
* Loads a BMP image into a texture on the rendering device
* @param file The BMP image file to load
* @param ren The renderer to load the texture onto
* @return the loaded texture, or nullptr if something went wrong.
*/
SDL_Texture* loadTexture(const std::string &file, SDL_Renderer *ren)
{
//Initialize to nullptr to avoid dangling pointer issues
SDL_Texture *texture = nullptr;
//Load the image
SDL_Surface *loadedImage = SDL_LoadBMP(file.c_str());
//If the loading went ok, convert to texture and return the texture
if (loadedImage != nullptr){
texture = SDL_CreateTextureFromSurface(ren, loadedImage);
SDL_FreeSurface(loadedImage);
//Make sure converting went ok too
if (texture == nullptr){
logSDLError(std::cout, "CreateTextureFromSurface");
}
}
else {
logSDLError(std::cout, "LoadBMP");
}
return texture;
}
/**
* Draw an SDL_Texture to an SDL_Renderer at position x, y, preserving
* the texture's width and height
* @param tex The source texture we want to draw
* @param ren The renderer we want to draw to
* @param x The x coordinate to draw to
* @param y The y coordinate to draw to
*/
void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, int x, int y)
{
//Setup the destination rectangle to be at the position we want
SDL_Rect dst;
dst.x = x;
dst.y = y;
//Query the texture to get its width and height to use
SDL_QueryTexture(tex, NULL, NULL, &dst.w, &dst.h);
SDL_RenderCopy(ren, tex, NULL, &dst);
}
void TW_CALL RunCA(void * /*clientData*/)
{
std::cout << "button 1 clicked" << std::endl;
tex = !tex;
}
void TW_CALL RunCB(void * /*clientData*/)
{
std::cout << "button 2 clicked" << std::endl;
circ = !circ;
}
//---------------------------------------
int main()
{
int size=10;
int alpha=100;
std::cout << "Resource path is: " << getResourcePath() << std::endl;
if (SDL_Init(SDL_INIT_EVERYTHING) != 0){
logSDLError(std::cout, "SDL_Init");
return 1;
}
SDL_Window *window = SDL_CreateWindow("Lesson 2", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (window == nullptr){
logSDLError(std::cout, "CreateWindow");
SDL_Quit();
return 1;
}
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1,
SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
if (renderer == nullptr){
logSDLError(std::cout, "CreateRenderer");
cleanup(window);
SDL_Quit();
return 1;
}
const std::string resPath = getResourcePath();
SDL_Texture *image = loadTexture(resPath + "image.bmp", renderer);
if (image == nullptr){
cleanup(image, renderer, window);
SDL_Quit();
return 1;
}
TwInit(TW_OPENGL, NULL);
TwWindowSize(SCREEN_WIDTH, SCREEN_HEIGHT);
TwBar *myBar;
myBar = TwNewBar("TestBar");
TwDefine(" GLOBAL help='example help' "); // Message added to the help bar.
TwAddButton(myBar, "Switch Texture", RunCA, NULL, " label='texture' ");
TwAddButton(myBar, "Switch Circle", RunCB, NULL, " label='circle' ");
TwAddVarRW(myBar, "width", TW_TYPE_INT32, &size, " keyIncr=w, keyDecr=s ");
TwAddVarRW(myBar, "alpha", TW_TYPE_INT32, &alpha, " ");
// Add 'quit' to 'bar': this is a modifiable (RW) variable of type TW_TYPE_BOOL32
// (a boolean stored in a 32 bits integer). Its shortcut is [ESC].
TwAddVarRW(myBar, "Quit", TW_TYPE_BOOL32, &quit,
" label='Quit?' true='+' false='-' key='ESC' help='Quit program.' ");
// main loop
while( !quit )
{
SDL_Event event;
int handled=1;
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
SDL_RenderClear(renderer);
if(tex)
renderTexture(image, renderer, 50, 50);
if(circ)
filledCircleRGBA(renderer,
100, 100,
size,
0, 255, 0, alpha);
TwDraw(); // draw the tweak bar(s)
SDL_RenderPresent(renderer);
while(SDL_PollEvent(&event))
{
handled = TwEventSDL(&event, SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
if( !handled )
{
//If user closes the window
if (event.type == SDL_QUIT){
std::cout << "window closed" << std::endl;
quit = true;
}
//If user presses any key
if (event.type == SDL_KEYDOWN){
std::cout << "key down" << std::endl;
}
//If user clicks the mouse
if (event.type == SDL_MOUSEBUTTONDOWN){
std::cout << "mouse clicked" << std::endl;
}
}
}
// SDL_Delay(10);
} // end of main loop
//cleanup
cleanup(image, renderer, window);
// Terminate AntTweakBar
TwTerminate();
SDL_Quit();
return 0;
}
Does anybody know what is going on and how this could be fixed or avoided? If not, maybe somebody could recommend a different approach for rendering simple geometric shapes and a GUI (to configure some parameters) in SDL2/C++ without too much effort.
I got around it by changing my development environment from OSX (10.11.1) to Linux (Ubuntu 14.04-3). Of course this is no "REAL" solution, but maybe this information can still help somebody.