diff --git a/data/basic.glsl b/data/basic.glsl new file mode 100644 index 0000000..08c3f69 --- /dev/null +++ b/data/basic.glsl @@ -0,0 +1,32 @@ +varying vec2 TEX0; + +#if defined(VERTEX) + +void main() +{ + TEX0 = vec2(gl_MultiTexCoord0.x, 1.0-gl_MultiTexCoord0.y)*1.0001; + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; +} + +#elif defined(FRAGMENT) + +uniform sampler2D Texture; + +void main() +{ + vec2 winsize = vec2(640.0,480.0); + vec2 pixpos = TEX0 * winsize; + float y = floor(pixpos.y); + if (mod(y,4.0) == 0.0) + { + vec4 color = texture2D(Texture, TEX0); + vec4 blend = vec4(0.8, 0.8, 0.8, 1.0); + gl_FragColor = color * blend; + } + else + { + gl_FragColor = texture2D(Texture, TEX0); + } +} + +#endif \ No newline at end of file diff --git a/jshader.cpp b/jshader.cpp new file mode 100644 index 0000000..36e240a --- /dev/null +++ b/jshader.cpp @@ -0,0 +1,231 @@ +#include "jshader.h" + +#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 + +namespace shader +{ + SDL_Window *win = nullptr; + SDL_Renderer *renderer = nullptr; + GLuint programId = 0; + SDL_Texture* backBuffer = nullptr; + SDL_Point win_size = {640, 480}; + SDL_FPoint tex_size = {320, 240}; + bool usingOpenGL; + GLuint texture_number; + GLuint nose; + + #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) { + // Create ID for shader + GLuint result = glCreateShader(shaderType); + // Add define depending on shader type + 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; + } + return result; + } + + GLuint compileProgram(const char* vertexShaderSource, const char* fragmentShaderSource) + { + GLuint programId = 0; + GLuint vtxShaderId, fragShaderId; + + programId = glCreateProgram(); + + vtxShaderId = compileShader(vertexShaderSource, GL_VERTEX_SHADER); + fragShaderId = compileShader(fragmentShaderSource?fragmentShaderSource:vertexShaderSource, 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; + } + + const bool init(SDL_Window* win, SDL_Texture* backBuffer, const char* vertexShader, const char* fragmentShader) + { + shader::win = win; + shader::renderer = SDL_GetRenderer(win); + shader::backBuffer = backBuffer; + SDL_GetWindowSize(win, &win_size.x, &win_size.y); + SDL_GetTextureSize(backBuffer, &tex_size.x, &tex_size.y); + printf("tex size: %fx%f\n", tex_size.x, tex_size.y); + SDL_PropertiesID props = SDL_GetTextureProperties(backBuffer); + texture_number = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_OPENGL_TEXTURE_NUMBER, -1); + printf("texture number: %i\n", texture_number); + int access = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_ACCESS_NUMBER, -1); + nose = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_OPENGL_TEXTURE_TARGET_NUMBER, -1); + printf("texture target number: %i\n", nose); + + if (access != SDL_TEXTUREACCESS_TARGET) + { + std::cout << "ERROR FATAL: La textura per al render ha de tindre SDL_TEXTUREACCESS_TARGET definit." << std::endl; + exit(1); + } + + const char * renderer_name = SDL_GetRendererName(renderer); + printf("rendererInfo.name: %s\n", renderer_name); + + if(!strncmp(renderer_name, "opengl", 6)) { +#ifndef __APPLE__ + if (!initGLExtensions()) { + std::cout << "WARNING: No s'han pogut inicialitzar les extensions d'OpenGL!" << std::endl; + usingOpenGL = false; + return false; + } +#endif + // Compilar el shader y dejarlo listo para usar. + programId = compileProgram(vertexShader, fragmentShader); + } else { + std::cout << "WARNING: El driver del renderer no es OpenGL." << std::endl; + usingOpenGL = false; + return false; + } + usingOpenGL = true; + return true; + } + + unsigned char pixels[512*240*4]; + + void render() + { + SDL_FlushRenderer(renderer); + SDL_SetRenderTarget(renderer, NULL); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderClear(renderer); + SDL_FlushRenderer(renderer); + + if (usingOpenGL) + { + GLint oldProgramId; + if (programId != 0) + { + glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgramId); + glUseProgram(programId); + } + + glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, 1); + //glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, pixels); + //if (glGetError()) { printf("GLGETERROR!\n"); exit(1);} + //GLint param; + //glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, ¶m); + //printf("tex width: %i\n", param); + glViewport(0, 0, win_size.x, win_size.y); + + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f(0.0f, 0.0f); + glVertex2f(0.0f, 0.0f); + glTexCoord2f(1.0f, 0.0f); + glVertex2f(tex_size.x, 0.0f); + glTexCoord2f(0.0f, 1.0f); + glVertex2f(0.0f, tex_size.y); + glTexCoord2f(1.0f, 1.0f); + glVertex2f(tex_size.x, tex_size.y); + glEnd(); + + SDL_GL_SwapWindow(win); + + if (programId != 0) glUseProgram(oldProgramId); + + } else { + SDL_RenderTexture(renderer, backBuffer, NULL, NULL); + SDL_RenderPresent(renderer); + } + if (glGetError()) { printf("GLERROR!\n"); exit(1); } + } +} diff --git a/jshader.h b/jshader.h new file mode 100644 index 0000000..f2dc8e3 --- /dev/null +++ b/jshader.h @@ -0,0 +1,44 @@ +#pragma once + +#include + +// TIPS: +// ======================================================================= +// Abans de crear el renderer, cridar a la següent funció: +// +// SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"); +// +// Aixó li diu que volem un renderer que use especificament opengl. A més, +// al crear el renderer li tenim que dir que el volem que use acceeració +// per hardware, i que soporte render a textura. Per exemple: +// +// SDL_Renderer *ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | +// SDL_RENDERER_TARGETTEXTURE); +// +// Per altra part, al crear la textura tenim que definir que puga ser target +// de renderitzat (SDL_TEXTUREACCESS_TARGET), per exemple: +// +// SDL_Texture *tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, +// SDL_TEXTUREACCESS_TARGET, 320, 240); +// +// Els shaders li'ls passem com una cadena, som nosaltres els que s'encarreguem +// de carregarlos de disc, amb fopen, ifstream, jfile o el que vullgues. +// Si els tens en un std::string, passa-li-la com "cadena.c_str()". +// +// Poden ser els dos el mateix arxiu, com fa libRetro, jo desde dins ja fique +// els defines necessaris. Si es el mateix arxiu, pots no ficar el quart paràmetre. +// +// Els shaders de libRetro no funcionen directament, hi ha que fer algunes modificacions. +// +// El pintat final de la teua escena l'has de fer com si "backBuffer" fora la pantalla. +// +// Ah! una cosa mes: al compilar, en Linux afegir "-lGL", en Windows afegir "-lopengl32". +// En Mac ni idea + +namespace shader +{ + const bool init(SDL_Window* win, SDL_Texture* backBuffer, + const char* vertexShader, const char* fragmentShader=nullptr); + + void render(); +} diff --git a/lagueirtofile b/lagueirtofile index a1a609f..91969c3 100644 --- a/lagueirtofile +++ b/lagueirtofile @@ -1,4 +1,4 @@ -libs = -lSDL3 +libs = -lSDL3 -lGL cppflags = -D LUA_USE_LINUX -D DEBUG -g -Wall executable = mini_debug sourcepath = . lua diff --git a/mini.cpp b/mini.cpp index 88b04ae..c6e7acc 100644 --- a/mini.cpp +++ b/mini.cpp @@ -5,6 +5,7 @@ #include "gif.h" #include "gifenc.h" #include "jail_audio.h" +#include "jshader.h" #define MAX_TEXTURES 100 @@ -78,6 +79,7 @@ bool should_quit = false; SDL_Window *mini_win; SDL_Renderer *mini_ren; SDL_Texture *mini_bak; +SDL_Texture *mini_shadertex; Uint32 windowID; Uint32 *pixels; int pitch; @@ -300,8 +302,9 @@ void createDisplay() { if (screen_zoom <= 0) screen_zoom = 1; while (screen_width*screen_zoom > desktop_width || screen_height*screen_zoom > desktop_height) screen_zoom--; - mini_win = SDL_CreateWindow(window_title, screen_width*screen_zoom, screen_height*screen_zoom, screen_fullscreen?SDL_WINDOW_FULLSCREEN:SDL_WINDOW_RESIZABLE); + mini_win = SDL_CreateWindow(window_title, screen_width*screen_zoom, screen_height*screen_zoom, SDL_WINDOW_OPENGL|(screen_fullscreen?SDL_WINDOW_FULLSCREEN:SDL_WINDOW_RESIZABLE)); windowID = SDL_GetWindowID(mini_win); + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"); mini_ren = SDL_CreateRenderer(mini_win, NULL); //SDL_CreateWindowAndRenderer(512,512,0,&mini_win,&mini_ren); //SDL_SetRenderLogicalPresentation(mini_ren, screen_width, screen_height); @@ -314,6 +317,12 @@ void createDisplay() { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Pixelformat incorrecte: %i\n", real_pixelformat); exit(1); } + mini_shadertex = SDL_CreateTexture(mini_ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, screen_width*screen_zoom, screen_height*screen_zoom); + SDL_SetTextureScaleMode(mini_shadertex, SDL_SCALEMODE_NEAREST); + + int filesize; + char *shaderfile = file_getfilebuffer("basic.glsl", filesize); + shader::init(mini_win, mini_shadertex, shaderfile); //SDL_GetWindowPosition(mini_win, &windowpos_x, &windowpos_y); } @@ -500,13 +509,18 @@ int main(int argc,char*argv[]){ mouse_just_pressed = 0; pad_just_pressed = SDL_GAMEPAD_BUTTON_INVALID; } + SDL_SetRenderTarget(mini_ren, mini_shadertex); SDL_SetRenderDrawColor(mini_ren, 0, 0, 0, 255); SDL_RenderClear(mini_ren); SDL_LockTexture(mini_bak, NULL, (void**)&pixels, &pitch); for (uint32_t i=0;isize;++i) pixels[i] = palette[screen_surface->p[i]]; SDL_UnlockTexture(mini_bak); - SDL_RenderTexture(mini_ren, mini_bak, NULL, NULL); - SDL_RenderPresent(mini_ren); + SDL_RenderTexture(mini_ren, mini_bak, NULL, NULL); //NEW + + shader::render(); + //SDL_RenderTexture(mini_ren, mini_bak, NULL, NULL); + //SDL_RenderPresent(mini_ren); + fps_counter++; if (SDL_GetTicks()>=(fps_timer+1000)) { fps = fps_counter; @@ -579,11 +593,12 @@ uint32_t *loadpal(const char* filename, uint16_t *palsize) { } void setpal(uint32_t *pal) { - memcpy(palette, pal, 1024); + for (int i=0; i<256; ++i) palette[i] = pal[i] | 0xff000000; + //memcpy(palette, pal, 1024); } void setcolor(uint8_t index, uint32_t color) { - palette[index] = color; + palette[index] = color | 0xff000000; } uint32_t getcolor(uint8_t index) {