I wish to have a semi-transparent SDL background (nothing to do with sub-surfaces or images), such that instead of having a black background it is actually transparent, but the other things I draw are not. My current code is a slightly modified copy of Code::Blocks' SDL project, similar to how various applications have rounded borders or odd shapes besides rectangles.
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#ifdef __APPLE__
#include <SDL/SDL.h>
#else
#include <SDL.h>
#endif
int main ( int argc, char** argv )
{
putenv("SDL_VIDEO_WINDOW_POS");
putenv("SDL_VIDEO_CENTERED=1");
// initialize SDL video
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
printf( "Unable to init SDL: %s\n", SDL_GetError() );
return 1;
}
// make sure SDL cleans up before exit
atexit(SDL_Quit);
// create a new window
SDL_Surface* screen = SDL_SetVideoMode(640, 480, 16,
SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_NOFRAME);
if ( !screen )
{
printf("Unable to set 640x480 video: %s\n", SDL_GetError());
return 1;
}
// load an image
SDL_Surface* bmp = SDL_LoadBMP("cb.bmp");
if (!bmp)
{
printf("Unable to load bitmap: %s\n", SDL_GetError());
return 1;
}
// centre the bitmap on screen
SDL_Rect dstrect;
dstrect.x = (screen->w - bmp->w) / 2;
dstrect.y = (screen->h - bmp->h) / 2;
// program main loop
bool done = false;
while (!done)
{
// message processing loop
SDL_Event event;
while (SDL_PollEvent(&event))
{
// check for messages
switch (event.type)
{
// exit if the window is closed
case SDL_QUIT:
done = true;
break;
// check for keypresses
case SDL_KEYDOWN:
{
// exit if ESCAPE is pressed
if (event.key.keysym.sym == SDLK_ESCAPE)
done = true;
break;
}
} // end switch
} // end of message processing
// DRAWING STARTS HERE
// clear screen
SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));
// draw bitmap
SDL_BlitSurface(bmp, 0, screen, &dstrect);
// DRAWING ENDS HERE
// finally, update the screen :)
SDL_Flip(screen);
} // end main loop
// free loaded bitmap
SDL_FreeSurface(bmp);
// all is well ;)
printf("Exited cleanly\n");
return 0;
}
I think what you're trying to do is in fact a shaped window (parts of the window are transparent depending on a mask that you provide). It seems there's no way to do that with SDL 1.2, however there is a SDL_SetWindowShape function just for this in SDL 1.3 for which you can find a pre-release snapshot here but it's not even in beta yet so I suggest waiting until it's officialy released :)
this is a link to a pretty neat article about development of an older application for Mac OS 9, which did not have support for shaped windows, either.
It's actually a neat article in general about software development.
But the idea seems pretty smart, and I wonder if you might be able to get it working here, too. Instead of trying to make a transparent background, they actually take a screen-shot of the computer right where their window is going to go, and then use that screen shot for their background. When the user drags the window around on the screen, they continue to update the background with new screen-shots. I think this might be more complicated than you were hoping for, but it's certainly an interesting idea.
Related
This test program should create a blank window that stays open until you x-it-out. I copied it from SDL's documentation to make sure it is correct. It can be found here.
// Example program:
// Using SDL2 to create an application window
#include "SDL.h"
#include <stdio.h>
int main(int argc, char* argv[]) {
SDL_Window *window; // Declare a pointer
SDL_Init(SDL_INIT_VIDEO); // Initialize SDL2
// Create an application window with the following settings:
window = SDL_CreateWindow(
"An SDL2 window", // window title
SDL_WINDOWPOS_UNDEFINED, // initial x position
SDL_WINDOWPOS_UNDEFINED, // initial y position
640, // width, in pixels
480, // height, in pixels
SDL_WINDOW_OPENGL // flags - see below
);
// Check that the window was successfully created
if (window == NULL) {
// In the case that the window could not be made...
printf("Could not create window: %s\n", SDL_GetError());
return 1;
}
//game loop, quitGame to quit
bool quitGame = false;
//var for checking events
SDL_Event event;
while(!quitGame) {
//Update particles
//Draw particles
//Check for events
while(SDL_PollEvent(&event)) {
if(event.type == SDL_QUIT)
quitGame = true;
}
}
// Close and destroy the window
SDL_DestroyWindow(window);
// Clean up
SDL_Quit();
return 0;
}
It doesn't create a window and terminates immediately, but gives no errors.
I'm using Eclipse, mingw32, and the latest stable release of SDL2. SDL2's libraries and headers are within a file in my C drive. I am using a 64 bit system. I include the entire folder of SDL2's header files. The only library folder I have linked is the one within the 64 bit part of the SDL2 folder. The libraries I have linked are the ones suggested by HolyBlackCat, (in this order) mingw32, SDL2main, and SDL2. Any help is greatly appreciated. Thanks!
I'm following this tutorial that teaches how to use SDL2 with the final goal of learning C++ in a more fun and interactive way.
For this, I only need to be able to draw lines, polygons and circles.
So, after reading part 1 that explains how to create a window on the screen and part 3 that introduces event handling, I headed torward part 7 and 8 that explain, respectively, how to create a renderer and how to draw a rectangle on the screen. This is the code I've got so far (it isn't exactly the same as the code on the tutorial: I've introduced a struct to pass SDL objects around and removed all the error handling which was confusing):
#include <SDL2/SDL.h>
//screen dimensions costants
#define SCREEN_WIDTH 540
#define SCREEN_HEIGHT 960
//data structure holding the objects needed to create a window and draw on it
struct interface {
SDL_Window * window = NULL;
SDL_Surface * surface = NULL;
SDL_Renderer * renderer = NULL;
};
//function which inits the sdl and creates an interface object
interface init() {
interface screen;
SDL_Init(SDL_INIT_VIDEO);
screen.window = SDL_CreateWindow("", 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
screen.surface = SDL_GetWindowSurface(screen.window);
screen.renderer = SDL_CreateRenderer(screen.window, -1, SDL_RENDERER_ACCELERATED);
return screen;
}
//function to free the memory and close the sdl application
void close(interface screen) {
SDL_DestroyRenderer(screen.renderer);
SDL_DestroyWindow(screen.window);
screen.renderer = NULL;
screen.window = NULL;
SDL_Quit();
}
int main(int argc, char* args[]) {
//start the application
interface screen = init();
//setup for event handling
bool quit = false;
SDL_Event event;
//the shape to render
SDL_Rect fillRect = { SCREEN_WIDTH / 4, SCREEN_HEIGHT / 4, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 };
//main loop which first handles events
while (!quit) {
while (SDL_PollEvent(&event) != 0) {
if (event.type == SDL_QUIT)
quit = true;
}
//should draw a red rectangle on the screen
SDL_SetRenderDrawColor(screen.renderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(screen.renderer);
SDL_SetRenderDrawColor(screen.renderer, 0xFF, 0x00, 0x00, 0xFF);
SDL_RenderFillRect(screen.renderer, &fillRect);
}
//End the application
close(screen);
return 0;
}
The problem is that, as it is, the program draws nothing to the screen (which remains black), and if I remove the line screen.surface = SDL_GetWindowSurface(screen.window); it also begins lagging a lot in a manner I even find difficult to exit the application.
Note that I'm programming on Android using C4droid and the SDL Plugin for C4droid.
Why is that happening? What am I doing wrong?
EDIT Problem solved by renaming close to end and by including a call to SDL_RenderPresent(screen.renderer); at the end of the main loop. With this setup the screen surface has to be deleted or the program won't draw anything.
Thanks to #keltar and #Wutipong Wongsakuldej for answering the question in the comments
First of all I tested the code in Windows (MSYS2) rather than on Android as I don't have AIDE installed at the moment.
Basically I added 2 lines of code into the main loop :
//main loop which first handles events
while (!quit) {
while (SDL_PollEvent(&event) != 0) {
if (event.type == SDL_QUIT)
quit = true;
}
//should draw a red rectangle on the screen
SDL_SetRenderDrawColor(screen.renderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(screen.renderer);
SDL_SetRenderDrawColor(screen.renderer, 0xFF, 0x00, 0x00, 0xFF);
SDL_RenderFillRect(screen.renderer, &fillRect);
/** below lines are added **/
SDL_RenderPresent(screen.renderer);
SDL_Delay(0);
}
SDL_RenderPresent draw whatever you've renderred so far to the screen. This make the output shows up.
SDL_Delay() this is added to give the cpu time back to the os. Without this your app might become unresponsive and the cpu utilization will be 100% (at one core) in some operating system (especially the very old one). I don't know if this is needed in Android or not anyway. Give it a try.
so I got the following code(piece):
_Bool create_new_window(rectanglestruct *rectangle, colorstruct *colorfill, char *winname)
{
....
log_printf("creating main renderer for window ( window : %s )\n", ptr->winname);
// Setup renderer
SDL_Renderer *renderer = SDL_CreateRenderer( ptr->window, -1, SDL_RENDERER_ACCELERATED);
ptr->renderer = renderer;
if (colorfill != NULL)
{
log_printf("\n - background color set r=%d g=%d b=%d with opacity of %d\n", colorfill->r,colorfill->g,colorfill->b, colorfill->opacity);
// Set render color to red ( background will be rendered in this color )
SDL_SetRenderDrawColor( ptr->renderer, colorfill->r,colorfill->g,colorfill->b, colorfill->opacity );
log_printf("background rendered\n");
}
// Clear window
SDL_RenderClear( ptr->renderer );
SDL_ShowWindow(ptr->window);
SDL_RenderPresent( ptr->renderer );
getchar();
with
typedef struct SDL_Window SDL_Window;
typedef struct windowstruct {
char *winname;
SDL_Window *window;
SDL_Renderer *renderer;
struct windowstruct *next;
struct windowstruct *previous;
} windowstruct;
static windowstruct *root = NULL;
and
typedef struct colorstruct {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t opacity;
} colorstruct;
With in main:
_Bool start_SDL(void)
// scope this
{
//draw background
colorstruct *colorfill = malloc(sizeof(rectanglestruct));
colorfill->r = 0xFF;
colorfill->g = 0xFF;
colorfill->b = 0xFF;
colorfill->opacity = 0xFF;
rectanglestruct *winplace = malloc(sizeof(rectanglestruct));
winplace->x = 0;
winplace->y = 0;
winplace->w = 300;
winplace->h = 300;
create_new_window(winplace, colorfill, "appscreen");
free(colorfill);
free(winplace);
}
and
_Bool start_SDL(void)
{
//Initialization flag
_Bool success = true;
//Initialize SDL
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
log_printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
success = false;
}
}
and I got the following output (after a couple of times):
The point is I thought that the renderer was just a copy of the screen like a buffer in which you can write and refresh on the screen. But I gues not?
No, SDL_Renderer implements SDL2 drawing, usually with hardware-accelerated backend. Your image is corrupt because you didn't issue redraw at appropriate time. If your window needs redraw (resized, overshadowed by other window or sceen borders) - you have to draw again and present result (this is in fact the same for every windowing library; even in GUI toolkits like Qt or GTK if your callback didn't return quickly, you can experience the same corruption). You can render to texture and then display it again if your image remains unchanged and calculations are heavy.
To do what you've said would require accumulating all data sent to renderer (may be high memory usage) and either calling update on regular intervals or on events, or taking away main loop from calling side (like most GUI toolkits do), which is against SDL design. Also, since SDL's main target are video games, scenes there are rarely static.
Before SDL2 there was no renderer and SDL only provided display surface to which you draw, but it is quite the same basic concept, it wouldn't update all by itself.
It doesn't mean it cannot be done with SDL, however - it gives you much more control. If you want to redraw only when it is really required - watch for SDL_WindowEvent.
I've got some code (below) that uses SDL_ttf and would like to:
Be able to render text (from the TTF) in alignment (to a buffer or array as well) like a console would (having each character printed in it's individual cell).
Be able to utilize a blinking cursor (possibly render and un-render an underscore, maybe?)
Be able to let the user input text from the keyboard and render each char on the screen right when it is typed (using SDLK_charhere).
Getting back to #1: I'm thinking about getting the width of the previous character printed on the screen (from the TTF) and using its width (in pixels) to print the next character right after the previous character, plus 2 pixels. <-- PLEASE TELL ME IF THE SPACING BETWEEN CHARS IN A REGULAR WIN32 CONSOLE IS A DIFFERENT SIZE IN PIXELS.
Here's the code that needs to be modified:
#include "include/SDL/SDL.h"
#include "include/SDL/SDL_ttf.h"
int currentX = 0;
int currentY = 0;
int newW;
int newH;
SDL_Surface* screen;
SDL_Surface* fontSurface;
SDL_Color fColor;
SDL_Rect fontRect;
SDL_Event event;
TTF_Font* font;
//Initialize the font, set to white
void fontInit(){
TTF_Init();
font = TTF_OpenFont("dos.ttf", 12);
fColor.r = 0; // 255
fColor.g = 204; // 255
fColor.b = 0; //255
}
//Print the designated string at the specified coordinates
void PrintStr(char *c, int x, int y){
fontSurface = TTF_RenderText_Solid(font, c, fColor);
fontRect.x = x;
fontRect.y = y;
SDL_BlitSurface(fontSurface, NULL, screen, &fontRect);
SDL_Flip(screen);
}
int main(int argc, char** argv)
{
// Initialize the SDL library with the Video subsystem
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
//Create the screen
screen = SDL_SetVideoMode(320, 480, 0, SDL_SWSURFACE);
//Initialize fonts
fontInit();
PrintStr("", 0, 0);
do {
// Process the events
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
// Escape forces us to quit the app
case SDLK_ESCAPE:
event.type = SDL_QUIT;
break;
default:
break;
}
break;
default:
break;
}
}
SDL_Delay(10);
} while (event.type != SDL_QUIT);
// Cleanup
SDL_Quit();
return 0;
}
This isn't a trivial thing to do, but it sounds like a good learning project! You're maybe going to need a few thousand lines of code rather than the few tens you have up there. Perhaps start by considering these questions and their answers.
Do you want a fixed width font, or a variable width font?
How can you buffer the rendered text in an intelligent way? (glyphs or lines for eg.)
How can you buffer the text itself in an intelligent way?
How can you translate key presses into text?
What is translating and driving all this?
All these will need to be considered along with the most important question of all:
Do I want to do this?
If you do do this, it will teach you a lot about programming, but it might not give you the best full screen console you're looking for.
I am having some issues with GLFW's window creation. I am wanting to have a program capable of toggling between windowed and fullscreen mode. To do this in GLFW 2.7.8 one must first destroy the active window, then create a new one. I read that version 3.0 has support for multiple windows, but it is still in development.
I have provided my own function to handle keyboard input. Using the initial 400 by 400 window, the program functions as expected; it will enter fullscreen on f or F, will exit when the escape key is pressed, and will complain when anything else is pressed.
However, when fullscreen mode is entered, the window becomes unresponsive with regards to my provided keyboard function. It will continue to run through the loop in main() and will respond to something like the glfwGetKey(GLFW_KEY_ESC) test. Regardless of if I have the mouse cursor enabled or not, the cursor does not appear.
Again, the fullscreen window is created and the KeyboardCallback function returns back into the main loop. I wish to understand why the fullscreen window is not working with my keyboard function, and why it is not displaying properly.
I am not drawing anything to the window, as I am trying to get some experience with various window abstraction libraries specifically. Drawing a simple triangle did nothing to solve he problem, and the fullscreen window remains black.
My code is as follows:
#include <stdio.h>
#include <stdlib.h>
// glfw32 - 2.7.8
#include <GL\glfw.h>
#pragma comment (lib, "GLFW.lib")
#pragma comment (lib, "opengl32.lib")
using namespace std;
// constants and globals
const int WINDOW_WIDTH=400, WINDOW_HEIGHT=400;
static bool fullscreen=false;
// function declarations
void GLFWCALL KeyboardCallback(int key, int action);
void FatalError(const char* msg) {
fprintf(stderr, "ERROR: Failure in \"%s\"\n", msg);
exit(1);
}
int main() {
// ititialize GLFW
glfwInit();
glfwEnable(GLFW_MOUSE_CURSOR);
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3);
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 3);
// initial window, 400x400 with 32-bit depth buffer in windowed mode
glfwOpenWindow(WINDOW_WIDTH, WINDOW_HEIGHT, 0,0,0,0, 32, 0, GLFW_WINDOW);
glfwSetWindowTitle("Simple Title");
glfwSetWindowPos(0, 0);
// set custom keyboard callback
glfwSetKeyCallback(KeyboardCallback);
while (true) { // loop until exit
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers();
// debug
//printf("Looping...\n");
if ( glfwGetKey(GLFW_KEY_ESC) ) {break;}
}
glfwTerminate();
printf("\nHave a nice day\n");
return 0;
}
void GLFWCALL KeyboardCallback(int key, int action) {
//printf("In keyboard function\n");
if (action) { // if key DOWN,
switch(key) { // do something...
case 'f':
case 'F': {
fullscreen = !fullscreen;
printf("Toggle Fullscreen: %s\n", (fullscreen ? "On" : "Off"));
glfwCloseWindow();
if (! glfwOpenWindow(WINDOW_WIDTH, WINDOW_HEIGHT, 0,0,0,0, 32, 0,
fullscreen ? GLFW_FULLSCREEN : GLFW_WINDOW)) {
FatalError("toggle fullscreen");
}
glfwSetWindowTitle("New Title");
break;
}
case GLFW_KEY_ESC: {
printf("\nGoodbye cruel world...\n");
glfwTerminate();
exit(0);
}
default: {
printf("Key not implemented: %c\n", key);
break;
}
}
}
printf("Exiting keyboard function\n");
}
I tried James' approach from here but to no effect. Are there GLFW flags I am forgetting to set?
EDIT------- 5/20
I had a thought. Perhaps my callback was being unregistered when the window is destroyed. Turns out that re-registering my function when the new window is created made the window responsive.
While this solves my original problem, I now face a new one. I cannot render to the new window properly. I can insert glClear( GL_COLOR_BUFFER_BIT ); into my main loop, which will successfully set a background colour for the new window. For some reason it does not interact with my arrays and buffers to draw the image.
Code with attempted drawing
EDIT------- 5/21
I converted my code to GLFW 3.0.0. The window management is much cleaner (albeit more complex) and I do not have the rendering issue. Probably because I explicitly have to state the current context to use.
I would still like to solve the rendering issue, both out of curiosity and for if/when I return to 2.7.
Right now the event queue of GLFW is not pumped. You must either set the GLFW_AUTO_POLL_EVENTS option so that glfwSwapBuffers pumps the event queue, or you call glfwPollEvents at the start of a main event loop iteration.