Related
I'm trying to update the window with a new additional rect upon key pressing, but it keeps disappearing due to SDL_RenderClear. Is it recommended to remove SDL_RenderClear?
while (!quit) {
while (SDL_PollEvent( & e) != 0) {
if (e.type == SDL_QUIT)
quit = true;
}
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(gRenderer); //if i remove this line, the new rectangle will remain there
SDL_Rect fillRect = {
0,
0,
SCREEN_WIDTH / 5 - 5,
SCREEN_HEIGHT / 5 - 5
};
SDL_SetRenderDrawColor(gRenderer, 255, 205, 51, 0xFF);
SDL_RenderFillRect(gRenderer, & fillRect);
switch (e.type) {
case SDL_KEYDOWN:
if (e.key.keysym.sym == SDLK_RIGHT) {
SDL_Rect fillRect = {
0,
200,
SCREEN_WIDTH / 5 - 5,
SCREEN_HEIGHT / 5 - 5
};
SDL_SetRenderDrawColor(gRenderer, 255, 205, 51, 0xFF);
SDL_RenderFillRect(gRenderer, & fillRect);
}
break;
}
SDL_RenderPresent(gRenderer);
}
SDL_RenderClear() is perfectly fine and in fact you should be using it. Your problem (aka the rect disappearing) is caused by the way you handle input. SDL_KEYDOWN is an event that only occurs on the frame that you press a key for, and while you're holding it down after a short delay. What you are doing is drawing the rect if the key has been pressed on that exact frame, not if it's been pressed on any previous frames. A solution via a bool could look like this:
bool keyPressed = false;
while( !quit ) {
while( SDL_PollEvent( &e ) != 0 ) {
if( e.type == SDL_QUIT )
quit = true;
}
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( gRenderer ); //if i remove this line, the new rectangle will remain there
SDL_Rect fillRect = { 0, 0, SCREEN_WIDTH / 5-5, SCREEN_HEIGHT / 5-5 };
SDL_SetRenderDrawColor( gRenderer, 255, 205, 51, 0xFF );
SDL_RenderFillRect( gRenderer, &fillRect );
if(keyPressed){
SDL_Rect fillRect = { 0, 200, SCREEN_WIDTH / 5-5, SCREEN_HEIGHT / 5-5 };
SDL_SetRenderDrawColor( gRenderer, 255, 205, 51, 0xFF );
SDL_RenderFillRect( gRenderer, &fillRect );
}
switch(e.type){
case SDL_KEYDOWN:
if(e.key.keysym.sym==SDLK_RIGHT){
keyPressed = true;
}
break;
}
SDL_RenderPresent( gRenderer );
}
Screen clearing is something that should absolutely be done in graphics, because otherwise the shapes you've drawn on previous frames will just remain there.
Here is my code, I am following lazyfoos tutorials on SDL, here is the exact tutorial I am following - http://lazyfoo.net/tutorials/SDL/08_geometry_rendering/index.php
Notice the call to SDL_SetRenderDrawColor. We're using 255 red and 255
green which combine together to make yellow. Remember that call to
SDL_SetRenderDrawColor at the top of the loop? If that wasn't there,
the screen would be cleared with whatever color was last set with
SDL_SetRenderDrawColor, resulting in a yellow background in this case.
Lazyfoo does explain it above but it still doesn't make sense to me.
To draw a filled rectangle to the screen is a pretty trivial task but it's a task that sometimes causes a lot of confusion,for example you need to call SDL_SetRenderDrawColor() not once but twice,once before you clear the renderer,and also once before you call SDL_RenderFillRect().
Why do you need to call SDL_SetRenderDrawColor() twice and why in that order? I noticed if I comment out the first SDL_SetRenderDrawColor() just before the call to SDL_RenderFillRect(),the full window will be the colour you set the rectangle to be,but when you include the two calls to SDL_SetRenderDrawColor() in the order I specified the window shows a coloured rectangle in the centre of the screen with the rest of the screen being white(first SDL_SetRenderDrawColor() call).
Here is my game loop where the calls are made.
while( !quit )
{
while( SDL_PollEvent( &event ) != 0 )
{
if( event.type == SDL_QUIT )
{
quit = true;
}
}
SDL_SetRenderDrawColor( renderer, 255, 255, 255, 0 ); // line of code in question
SDL_RenderClear( renderer );
SDL_Rect fillRect = { 500 / 4, 500 / 4, 500 / 2, 500 / 2 };
SDL_SetRenderDrawColor( renderer, 0x00, 0xFF, 0x00, 0xFF ); // 2nd line of code in question
SDL_RenderFillRect( renderer, &fillRect );
SDL_RenderPresent( renderer );
}
Why do you need to call SDL_SetRenderDrawColor() twice and why in that
order?
The name of SDL_RenderClear is a bit misleading. It doesn't clear the screen to "empty" or anything - it just fills it with whatever color was set by SDL_SetRenderDrawColor. So if you don't change the color between "clearing" and drawing the rectangle, then you won't see the rectangle because you're drawing it with the same color that you just filled the entire screen with.
So here
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( gRenderer );
You make the whole screen white. We do this by setting white, and then painting over the entire screen with white.
Then here
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0x00, 0x00, 0xFF );
We set red so the rectangle here
SDL_RenderFillRect( gRenderer, &fillRect );
Will be red (not white).
And if I remember the tutorial correctly, it also draws a line and some other things, every time calling SDL_SetRenderDrawColor right before to set the correct color.
I noticed if I comment out the first SDL_SetRenderDrawColor() just
before the call to SDL_RenderFillRect(),the full window will be the
colour you set the rectangle to be
Very good observation! You see, since you're looping (while(!quit){) you do SDL_RenderClear and then SDL_RenderFillRect... but then SDL_RenderClear comes again, and so on. So when SDL_RenderClear happens, the color was actually set from right before SDL_RenderFillRect in the last run through the loop. Hence why it has that color, too.
So actually, I don't know what the color is at the very first time because it's not set yet (might be a default value of white, or something), but we probably can't see it because that's just on the first run through the loop anyway. So what happens roughly is:
...
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor( renderer, 0x00, 0xFF, 0x00, 0xFF );
SDL_RenderFillRect( renderer, &fillRect );
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor( renderer, 0x00, 0xFF, 0x00, 0xFF );
SDL_RenderFillRect( renderer, &fillRect );
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor( renderer, 0x00, 0xFF, 0x00, 0xFF );
SDL_RenderFillRect( renderer, &fillRect );
...
So you see, with only that second SDL_SetRenderDrawColor call, both SDL_RenderClear and SDL_RenderFillRect will always draw in green, except the very first SDL_RenderClear call in the first frame.
After most of the curriculum, they spring C++ on us for the senior year. Sigh. So I'm underwater trying to learn it and OpenGL, the latter being the actual subject of the class.
Please, why does this thing run twice? This assignment has already been turned in and graded, so but I just can't find any good online guide to OpenGL. Thanks for any thoughts.
#ifdef __APPLE__
#include <GLUT/glut.h>
#include <OpenGL/gl.h>
#else
#include <GL/glut.h>
#endif
#include <stdlib.h>
int width = 800, height = 600;
float xmin = -(width / 2), ymin = -(height / 2), xmax = width / 2, ymax = height / 2;
GLubyte bitmap[72] = { 0x00, 0x00, 0x00,
0x40, 0x00, 0x02,
0x20, 0x00, 0x04,
0x10, 0x38, 0x08,
0x09, 0x63, 0x10,
0x06, 0x00, 0xA0,
0x08, 0x00, 0x20,
0x10, 0x00, 0x10,
0x10, 0x00, 0x10,
0x10, 0x00, 0x08,
0x20, 0x00, 0x08,
0x20, 0x10, 0x08,
0x20, 0x18, 0x08,
0x10, 0x14, 0x08,
0x10, 0x12, 0x10,
0x10, 0x11, 0x10,
0x08, 0x10, 0x20,
0x04, 0x10, 0x40,
0x01, 0x87, 0x00,
0x00, 0x78, 0x00,
0x00, 0x00, 0x00,
0x00, 0x00, 0x00,
0x00, 0x00, 0x00,
0x00, 0x00, 0x00
};
void init(void) {
// Set display-window color to white.
glClearColor(0.0, 0.0, 1.0, 0.0);
// Set projection parameters.
glMatrixMode(GL_PROJECTION);
gluOrtho2D(xmin,xmax,ymin,ymax);
// Clear display window.
glClear(GL_COLOR_BUFFER_BIT);
glutSwapBuffers();
}
// Windows redraw function
void winReshapeFcn(GLint newWidth, GLint newHeight) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-(GLdouble)width / 2, (GLdouble)width / 2, -(GLdouble)height / 2, (GLdouble)height / 2);
glClear(GL_COLOR_BUFFER_BIT);
}
void drawText() {
int x = (int) xmin + 20, y = (int) ymax - 20, count = 0;
char what [] = { 'R', 'e', 'c', 't', 'a', 'n', 'g', 'l', 'e', 's' };
float color = 1.0;
glRasterPos2i(x, y);
do {
glColor3f(color,color,color);
color = color - 0.1;
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, what[count]);
y = y - 20;
glRasterPos2i(x, y);
count = count + 1;
} while (count <= 9);
}
void drawRectangles() {
int h = (int) ymax, x1 = -h, y1 = h, x2 = h, y2 = -h, count = 0, delta, factor = 5;
do {
glBegin(GL_LINES);
glVertex2i(x1,h);
glVertex2i(h,y1);
glVertex2i(h,y1);
glVertex2i(x2,-h);
glVertex2i(x2,-h);
glVertex2i(-h,y2);
glVertex2i(-h,y2);
glVertex2i(x1,h);
glEnd();
h = h - factor; delta = factor * count;
x1 = -h + delta; y1 = h - delta; x2 = h - delta; y2 = -h + delta;
count = count + 1;
} while (x1 < h);
}
void drawBitmaps() {
int count = 0;
GLfloat xorigin = xmin + (xmax - ymax) / 2.0;
// Needed for reading from memory. 1 indicates byte alignment
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Center the bitmap image
glRasterPos2i(0, 0);
do {
glBitmap(24.0, 24.0, xorigin, ymax, 0.0, 24.0, bitmap);
count = count + 24;
Sleep(150);
glutSwapBuffers();
} while ((count < width) && (count < height));
}
void displayFunction(void) {
// Clear display window.
glClear(GL_COLOR_BUFFER_BIT);
// Set graphic objects color to Red or change for your choice
drawText();
glColor3f(1.0, 1.0, 0.0);
drawRectangles();
drawBitmaps();
// Execute OpenGL functions
glFlush();
}
void main(int argc, char** argv) {
// Initialize GLUT.
glutInit(&argc, argv);
// Set display mode.
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
// Set top-left display-window position.
glutInitWindowPosition((glutGet(GLUT_SCREEN_WIDTH) - width) / 2, (glutGet(GLUT_SCREEN_HEIGHT) - height) / 2);
// Set display-window width and height.
glutInitWindowSize(width, height);
// Create display window.
glutCreateWindow("Michael Powers - Homework 2");
// Execute initialization procedure.
init();
// Send graphics to display window.
glutDisplayFunc(displayFunction);
// Window reshape call
glutReshapeFunc(winReshapeFcn);
// Display everything and wait.
glutMainLoop();
}
The GLUT display function displayFunction gets called every time the graphics need to be rendered again. On a real OpenGL app it would be called continuously, controlled by a timer. Here it gets called once when the window it opened. But depending on the OS, it may be called multiple times, for example if the window needs to be refreshed because it got activated.
In the code the animation is controlled by Sleep(150) and glutSwapBuffers() during the execution of displayFunction(). So the application blocks during the animation, but the graphics are still shown because of the glutSwapBuffers() calls.
Normally a display function should execute quickly (and never block/wait), and call glFlush() and glutSwapBuffers() only once at the end.
A better implementation would be: The state of the animation (i.e. the number of clock icons) is stored in a global variable int state = 0. displayFunction() always draws that number of clocks without waiting, and then exits. Before starting the main loop a timer is registered with glutTimerFunc, with a function that increments state, and then calls glutPostRedisplay(). This schedules GLUT to recall the display function. Then the app also remains responsive during the animation, and can be quit by closing the window.
I've got an OSX app that uses OpenGL. I'm drawing most of my stuff with textures of the type GL_TEXTURE_2D, and everything works fine as long as I stick to GL_TEXTURE_2D. But I need to have a couple of textures of type GL_TEXTURE_RECTANGLE_ARB.
To create a texture of type GL_TEXTURE_RECTANGLE_ARB I do the following:
// 4x4 RGBA texture data
GLubyte TexData[4*4*4] =
{
0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff,
0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff,
0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff,
0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
};
GLuint myArbTexture;
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glGenTextures(1, &myArbTexture);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myArbTexture);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAX_LEVEL, 0 );
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, TexData);
To draw the texture I do the following:
SetupMyShader();
SetupMyMatrices();
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myArbTexture);
DrawMyQuads();
My shader is very simple:
void main (void)
{
gl_FragColor = texture2D(Tex, v_texcoords)*u_color;
}
Using the above code, my shader always references the last texture used in:
glBindTexture(GL_TEXTURE_2D, lastTexture)
instead of referencing the texture specified in:
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myArbTexture);
Some things to make note of:
After every GL call I'm checking for errors glGetError() and I don't get any errors.
If I replace GL_TEXTURE_RECTANGLE_ARB with GL_TEXTURE_2D everything works fine
This is not an issue with uv (st) coordinates. When drawing with GL_TEXTURE_2D my uv are 0->1 and with GL_TEXTURE_RECTANGLE_ARB my uv are 0->texWidth or texHeight
I'm running a pretty new mac that reports GL Version 2.1 NVIDIA-10.2.1 310.41.15f01 so it certainly should support GL_TEXTURE_RECTANGLE_ARB. (I would think anyway)
I've narrowed down the issue enough to be pretty darn sure that when rendering the shader always refers to the previous texture that was bound as GL_TEXTURE_2D. My quad always draws in the right place and with sensible uv coords, it's just that it is referencing the wrong texture.
So, anyone got any guesses what I'm missing? Is there some call that I should be making other than glBindTexture that my shader would need when using GL_TEXTURE_RECTANGLE_ARB?
You will need to update your shader code to use rectangle textures. The uniform needs to be declared as:
uniform sampler2DRect Tex;
and accessed with:
gl_FragColor = texture2DRect(Tex, v_texcoords)*u_color;
Another aspect to keep in mind is that texture coordinates are defined differently for rectangle textures. Instead of the normalized texture coordinates in the range 0.0 to 1.0 used by all other texture types, rectangle textures use non-normalized texture coordinates in the range 0.0 to width and 0.0 to height.
The following code is intended to display a green square on a black background. It executes, but the green square does not show up. However, if I change SDL_DisplayFormatAlpha to SDL_DisplayFormat the square is rendered correctly.
So what don't I understand? It seems to me that I am creating *surface with an alpha mask and I am using SDL_MapRGBA to map my green color, so it would be consistent to use SDL_DisplayFormatAlpha as well.
(I removed error-checking for clarity, but none of the SDL API calls fail in this example.)
#include <SDL.h>
int main(int argc, const char *argv[])
{
SDL_Init( SDL_INIT_EVERYTHING );
SDL_Surface *screen = SDL_SetVideoMode(
640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF
);
SDL_Surface *temp = SDL_CreateRGBSurface(
SDL_HWSURFACE, 100, 100, 32, 0, 0, 0,
( SDL_BYTEORDER == SDL_BIG_ENDIAN ? 0x000000ff : 0xff000000 )
);
SDL_Surface *surface = SDL_DisplayFormatAlpha( temp );
SDL_FreeSurface( temp );
SDL_FillRect(
surface, &surface->clip_rect, SDL_MapRGBA(
screen->format, 0x00, 0xff, 0x00, 0xff
)
);
SDL_Rect r;
r.x = 50;
r.y = 50;
SDL_BlitSurface( surface, NULL, screen, &r );
SDL_Flip( screen );
SDL_Delay( 1000 );
SDL_Quit();
return 0;
}
I was using the wrong format for SDL_MapRGBA. Should have been
SDL_FillRect(
surface, NULL, SDL_MapRGBA(
surface->format, 0xff, 0xff, 0x00, 0xff
)
);
(surface->format instead of screen->format.) I thought the two would be equivalent. And they are after calling SDL_DisplayFormat(), but not after calling SDL_DisplayFormatAlpha(). The screen surface doesn't have an alpha channel, so the format is different between the two.
(Cross-posted from gamedev.stackexchange.com)