#include #include #include #include #include #include #ifdef __APPLE__ #include "CoreFoundation/CoreFoundation.h" #include #if ESSENTIAL_GL_PRACTICES_SUPPORT_GL3 #include #else #include #endif //!ESSENTIAL_GL_PRACTICES_SUPPORT_GL3 #else #include #include #endif const int WIN_WIDTH = 1024; const int WIN_HEIGHT = 768; const int WORLD_WIDTH = 320; const int WORLD_HEIGHT = 240; struct sprite { float x; float y; float vx; float vy; }; const int MAX_SPRITES = 20; #ifndef __APPLE__ // I'm avoiding the use of GLEW or some extensions handler, but that // doesn't mean you should... PFNGLCREATESHADERPROC glCreateShader; PFNGLSHADERSOURCEPROC glShaderSource; PFNGLCOMPILESHADERPROC glCompileShader; PFNGLGETSHADERIVPROC glGetShaderiv; PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; PFNGLDELETESHADERPROC glDeleteShader; PFNGLATTACHSHADERPROC glAttachShader; PFNGLCREATEPROGRAMPROC glCreateProgram; PFNGLLINKPROGRAMPROC glLinkProgram; PFNGLVALIDATEPROGRAMPROC glValidateProgram; PFNGLGETPROGRAMIVPROC glGetProgramiv; PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; PFNGLUSEPROGRAMPROC glUseProgram; bool initGLExtensions() { glCreateShader = (PFNGLCREATESHADERPROC)SDL_GL_GetProcAddress("glCreateShader"); glShaderSource = (PFNGLSHADERSOURCEPROC)SDL_GL_GetProcAddress("glShaderSource"); glCompileShader = (PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader"); glGetShaderiv = (PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv"); glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)SDL_GL_GetProcAddress("glGetShaderInfoLog"); glDeleteShader = (PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader"); glAttachShader = (PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader"); glCreateProgram = (PFNGLCREATEPROGRAMPROC)SDL_GL_GetProcAddress("glCreateProgram"); glLinkProgram = (PFNGLLINKPROGRAMPROC)SDL_GL_GetProcAddress("glLinkProgram"); glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)SDL_GL_GetProcAddress("glValidateProgram"); glGetProgramiv = (PFNGLGETPROGRAMIVPROC)SDL_GL_GetProcAddress("glGetProgramiv"); glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)SDL_GL_GetProcAddress("glGetProgramInfoLog"); glUseProgram = (PFNGLUSEPROGRAMPROC)SDL_GL_GetProcAddress("glUseProgram"); return glCreateShader && glShaderSource && glCompileShader && glGetShaderiv && glGetShaderInfoLog && glDeleteShader && glAttachShader && glCreateProgram && glLinkProgram && glValidateProgram && glGetProgramiv && glGetProgramInfoLog && glUseProgram; } #endif GLuint compileShader(const char* source, GLuint shaderType) { //std::cout << "Compilando shader:" << std::endl << source << std::endl; // Create ID for shader GLuint result = glCreateShader(shaderType); const char *sources[2] = { shaderType==GL_VERTEX_SHADER?"#define VERTEX\n":"#define FRAGMENT\n", source }; // Define shader text glShaderSource(result, 2, sources, NULL); // Compile shader glCompileShader(result); //Check vertex shader for errors GLint shaderCompiled = GL_FALSE; glGetShaderiv( result, GL_COMPILE_STATUS, &shaderCompiled ); if( shaderCompiled != GL_TRUE ) { std::cout << "Error en la compilación: " << result << "!" << std::endl; GLint logLength; glGetShaderiv(result, GL_INFO_LOG_LENGTH, &logLength); if (logLength > 0) { GLchar *log = (GLchar*)malloc(logLength); glGetShaderInfoLog(result, logLength, &logLength, log); std::cout << "Shader compile log:" << log << std::endl; free(log); } glDeleteShader(result); result = 0; } else { std::cout << "Shader compilado correctamente. Id = " << result << std::endl; } return result; } GLuint compileProgram(const char* vtxFile, const char* fragFile) { GLuint programId = 0; GLuint vtxShaderId, fragShaderId; programId = glCreateProgram(); std::ifstream f(vtxFile); std::string source((std::istreambuf_iterator(f)), std::istreambuf_iterator()); vtxShaderId = compileShader(source.c_str(), GL_VERTEX_SHADER); f=std::ifstream(fragFile); source=std::string((std::istreambuf_iterator(f)), std::istreambuf_iterator()); fragShaderId = compileShader(source.c_str(), GL_FRAGMENT_SHADER); if(vtxShaderId && fragShaderId) { // Associate shader with program glAttachShader(programId, vtxShaderId); glAttachShader(programId, fragShaderId); glLinkProgram(programId); glValidateProgram(programId); // Check the status of the compile/link GLint logLen; glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &logLen); if(logLen > 0) { char* log = (char*) malloc(logLen * sizeof(char)); // Show any errors as appropriate glGetProgramInfoLog(programId, logLen, &logLen, log); std::cout << "Prog Info Log: " << std::endl << log << std::endl; free(log); } } if(vtxShaderId) { glDeleteShader(vtxShaderId); } if(fragShaderId) { glDeleteShader(fragShaderId); } return programId; } void presentBackBuffer(SDL_Renderer *renderer, SDL_Window* win, SDL_Texture* backBuffer, GLuint programId) { GLint oldProgramId; // Guarrada para obtener el textureid (en driverdata->texture) //Detach the texture SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_SetRenderTarget(renderer, NULL); SDL_RenderClear(renderer); SDL_GL_BindTexture(backBuffer, NULL, NULL); if(programId != 0) { glGetIntegerv(GL_CURRENT_PROGRAM,&oldProgramId); glUseProgram(programId); } GLfloat minx, miny, maxx, maxy; GLfloat minu, maxu, minv, maxv; // Coordenadas de la ventana donde pintar. minx = 0.0f; miny = 0.0f; maxx = WORLD_WIDTH; maxy = WORLD_HEIGHT; minu = 0.0f; maxu = 1.0f; minv = 0.0f; maxv = 1.0f; glViewport(0, 0, WIN_WIDTH, WIN_HEIGHT); glBegin(GL_TRIANGLE_STRIP); glTexCoord2f(minu, minv); glVertex2f(minx, miny); glTexCoord2f(maxu, minv); glVertex2f(maxx, miny); glTexCoord2f(minu, maxv); glVertex2f(minx, maxy); glTexCoord2f(maxu, maxv); glVertex2f(maxx, maxy); glEnd(); SDL_GL_SwapWindow(win); if(programId != 0) { glUseProgram(oldProgramId); } } #ifdef __APPLE__ void initializeFileSystem() { CFBundleRef mainBundle = CFBundleGetMainBundle(); CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle); char path[PATH_MAX]; if (!CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, PATH_MAX)) { std::cerr << "Couldn't get file system representation! " << std::endl; } CFRelease(resourcesURL); chdir(path); } #endif int main(int argc, char **argv){ if (argc < 2) { std::cerr << "Uso: shaders [vertex shader] [fragment shader]" << "\n"; std::cerr << " shaders [unique shader]" << "\n"; return 1; } char *vertex_shader = argv[1]; char *fragment_shader = argc<3 ? vertex_shader : argv[2]; GLuint programId; #ifdef __APPLE__ initializeFileSystem(); #endif if (SDL_Init(SDL_INIT_EVERYTHING | SDL_VIDEO_OPENGL) != 0){ std::cerr << "SDL_Init failed: " << SDL_GetError() << "\n"; return 1; } SDL_Window *win = SDL_CreateWindow("Custom shader with SDL2 renderer!", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WIN_WIDTH, WIN_HEIGHT, 0); SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"); SDL_Renderer *renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE); SDL_RendererInfo rendererInfo; SDL_GetRendererInfo(renderer, &rendererInfo); if(!strncmp(rendererInfo.name, "opengl", 6)) { std::cout << "Es OpenGL!" << std::endl; #ifndef __APPLE__ // If you want to use GLEW or some other GL extension handler, do it here! if (!initGLExtensions()) { std::cout << "Couldn't init GL extensions!" << std::endl; SDL_Quit(); exit(-1); } #endif // Compilar el shader y dejarlo listo para usar. programId = compileProgram(vertex_shader, fragment_shader); std::cout << "programId = " << programId << std::endl; } //Put your own bmp image here SDL_Surface *bmpSurf = IMG_Load("image.png"); SDL_Texture *bmpTex = SDL_CreateTextureFromSurface(renderer, bmpSurf); SDL_FreeSurface(bmpSurf); //Make a target texture to render too SDL_Texture *texTarget = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, WORLD_WIDTH, WORLD_HEIGHT); int done = 0; int useShader = 0; SDL_Rect targetRect; targetRect.x = 0; targetRect.y=0; targetRect.w=32; targetRect.h=32; struct sprite sprites[MAX_SPRITES]; for(int i=0;i < MAX_SPRITES;++i) { sprites[i].x = (float) (rand() % (WORLD_WIDTH - targetRect.w)); sprites[i].y = (float) (rand() % (WORLD_HEIGHT - targetRect.h)); sprites[i].vx = (float) (rand() % 5 / 10.0f) - 0.2f; sprites[i].vy = (float) (rand() % 5 / 10.0f) - 0.2f; } // Voy a poner el fondo blanco para que se vea el shader SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); while ( ! done ) { //Render to the texture SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); SDL_SetRenderTarget(renderer, texTarget); SDL_RenderClear(renderer); // Pintamos MAX_SPRITES UWOLes struct sprite* spr; for(int i=0;i < MAX_SPRITES;++i) { spr = &(sprites[i]); spr->x += spr->vx; if(spr->x < 0) { spr->x = 0; spr->vx *= -1; } if(spr->x > WORLD_WIDTH - targetRect.w) { spr->x = (float) (WORLD_WIDTH - targetRect.w); spr->vx *= -1; } spr->y += spr->vy; if(spr->y < 0) { spr->y = 0; spr->vy *= -1; } if(spr->y > WORLD_HEIGHT - targetRect.h) { spr->y = (float) (WORLD_HEIGHT - targetRect.h); spr->vy *= -1; } targetRect.x = (int)spr->x; targetRect.y = (int)spr->y; SDL_RenderCopy(renderer, bmpTex, NULL, &targetRect); } presentBackBuffer(renderer, win, texTarget, programId); /* This could go in a separate function */ SDL_Event event; while ( SDL_PollEvent(&event) ) { if ( event.type == SDL_QUIT ) { done = 1; } if ( event.type == SDL_KEYDOWN ) { if ( event.key.keysym.sym == SDLK_SPACE ) { useShader ^= 1; std::cout << "useShader = " << (useShader ? "true" : "false") << std::endl; } if ( event.key.keysym.sym == SDLK_ESCAPE ) { done = 1; } } } } SDL_DestroyTexture(texTarget); SDL_DestroyTexture(bmpTex); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(win); SDL_Quit(); return 0; }