the frexel situation has improved significantly since the invention of upscaling
This commit is contained in:
parent
0f5e6d9a4d
commit
7ca0d351f7
@ -34,7 +34,7 @@ clean:
|
|||||||
${RM} -r ${ns}/
|
${RM} -r ${ns}/
|
||||||
|
|
||||||
${ns}/${NAME}.${EXTENSION}: ${objs}
|
${ns}/${NAME}.${EXTENSION}: ${objs}
|
||||||
${LD} ${ldflags} -o $@ $^
|
${LD} -o $@ $^ ${ldflags}
|
||||||
|
|
||||||
${ns}/%.o: src/%.c | ${ns}/
|
${ns}/%.o: src/%.c | ${ns}/
|
||||||
${CC} ${cflags} -c -o $@ -MMD -MP -MF ${@:.o=.d} $<
|
${CC} ${cflags} -c -o $@ -MMD -MP -MF ${@:.o=.d} $<
|
||||||
|
|||||||
@ -23,7 +23,7 @@ void main(void) {
|
|||||||
uniform sampler2D uTex;
|
uniform sampler2D uTex;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
vec4 Color = texture2D(uTex, vTexCoord)
|
vec4 Color = texture2D(uTex, vTexCoord);
|
||||||
if (Color.a < 0.5) {
|
if (Color.a < 0.5) {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
|
|||||||
183
src/main.c++
183
src/main.c++
@ -13,15 +13,23 @@
|
|||||||
#include "assets.h++"
|
#include "assets.h++"
|
||||||
#include "main.h++"
|
#include "main.h++"
|
||||||
|
|
||||||
#define WINDOW_WIDTH 128
|
#define WINDOW_VIRTUAL 128 // screen buffer, ideally with some padding for the offscreen
|
||||||
#define WINDOW_HEIGHT 128
|
#define WINDOW_WIDTH 128 // viewport width
|
||||||
|
#define WINDOW_HEIGHT 128 // viewport height
|
||||||
|
#define WINDOW_DENOM 128 // highest common denominator of width and height, for square pixel purposes
|
||||||
|
|
||||||
#define BATCH_SIZE 1024
|
#define BATCH_SIZE 1024
|
||||||
|
|
||||||
SDL_Window *window;
|
SDL_Window *window;
|
||||||
|
int16_t window_width = WINDOW_WIDTH, window_height = WINDOW_HEIGHT;
|
||||||
SDL_GLContext context;
|
SDL_GLContext context;
|
||||||
std::unordered_map<std::string, unsigned> programs;
|
std::unordered_map<std::string, unsigned> programs;
|
||||||
std::unordered_map<std::string, struct texture> textures;
|
std::unordered_map<std::string, struct texture> textures;
|
||||||
|
GLuint framebuffer = 0;
|
||||||
|
|
||||||
|
bool square_pixels = true, integer_upscale = false;
|
||||||
|
|
||||||
|
static int framebuffer_init(void);
|
||||||
|
|
||||||
SDL_AppResult SDL_AppInit(void **, int argc, char **argv) {
|
SDL_AppResult SDL_AppInit(void **, int argc, char **argv) {
|
||||||
clock_t begin = clock();
|
clock_t begin = clock();
|
||||||
@ -33,7 +41,7 @@ SDL_AppResult SDL_AppInit(void **, int argc, char **argv) {
|
|||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||||
SDL_SetHint(SDL_HINT_MAIN_CALLBACK_RATE, "60");
|
SDL_SetHint(SDL_HINT_MAIN_CALLBACK_RATE, "60");
|
||||||
|
|
||||||
window = SDL_CreateWindow("suwi", WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL /*| SDL_WINDOW_RESIZABLE*/ | SDL_WINDOW_TRANSPARENT);
|
window = SDL_CreateWindow("suwi", WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_TRANSPARENT);
|
||||||
SDL_SetWindowMinimumSize(window, WINDOW_WIDTH, WINDOW_HEIGHT);
|
SDL_SetWindowMinimumSize(window, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||||
|
|
||||||
context = SDL_GL_CreateContext(window);
|
context = SDL_GL_CreateContext(window);
|
||||||
@ -75,7 +83,8 @@ SDL_AppResult SDL_AppInit(void **, int argc, char **argv) {
|
|||||||
|
|
||||||
batch_init(BATCH_SIZE, programs.at("spr2D"));
|
batch_init(BATCH_SIZE, programs.at("spr2D"));
|
||||||
|
|
||||||
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
|
framebuffer_init();
|
||||||
|
|
||||||
SDL_ShowWindow(window);
|
SDL_ShowWindow(window);
|
||||||
|
|
||||||
fprintf(stderr, "info: init took %lu ms\n", ((clock() - begin) * 1000) / CLOCKS_PER_SEC);
|
fprintf(stderr, "info: init took %lu ms\n", ((clock() - begin) * 1000) / CLOCKS_PER_SEC);
|
||||||
@ -90,6 +99,13 @@ SDL_AppResult SDL_AppEvent(void *, SDL_Event *evt) {
|
|||||||
|
|
||||||
case SDL_EVENT_KEY_DOWN:
|
case SDL_EVENT_KEY_DOWN:
|
||||||
case SDL_EVENT_KEY_UP:
|
case SDL_EVENT_KEY_UP:
|
||||||
|
if (!evt->key.repeat && evt->key.down == true) {
|
||||||
|
if (evt->key.scancode == SDL_SCANCODE_1) {
|
||||||
|
square_pixels = !square_pixels;
|
||||||
|
} else if (evt->key.scancode == SDL_SCANCODE_2) {
|
||||||
|
integer_upscale = !integer_upscale;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_MOUSE_MOTION:
|
case SDL_EVENT_MOUSE_MOTION:
|
||||||
@ -104,13 +120,21 @@ SDL_AppResult SDL_AppEvent(void *, SDL_Event *evt) {
|
|||||||
case SDL_EVENT_WINDOW_MAXIMIZED:
|
case SDL_EVENT_WINDOW_MAXIMIZED:
|
||||||
case SDL_EVENT_WINDOW_RESTORED:
|
case SDL_EVENT_WINDOW_RESTORED:
|
||||||
case SDL_EVENT_WINDOW_MOVED:
|
case SDL_EVENT_WINDOW_MOVED:
|
||||||
|
break;
|
||||||
case SDL_EVENT_WINDOW_RESIZED:
|
case SDL_EVENT_WINDOW_RESIZED:
|
||||||
|
window_width = evt->window.data1;
|
||||||
|
window_height = evt->window.data2;
|
||||||
|
break;
|
||||||
case SDL_EVENT_WINDOW_MOUSE_ENTER:
|
case SDL_EVENT_WINDOW_MOUSE_ENTER:
|
||||||
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
|
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
|
||||||
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
||||||
case SDL_EVENT_WINDOW_FOCUS_LOST:
|
case SDL_EVENT_WINDOW_FOCUS_LOST:
|
||||||
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
||||||
break;
|
break;
|
||||||
|
case SDL_EVENT_WINDOW_EXPOSED:
|
||||||
|
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
||||||
|
case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED:
|
||||||
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_CLIPBOARD_UPDATE:
|
case SDL_EVENT_CLIPBOARD_UPDATE:
|
||||||
break;
|
break;
|
||||||
@ -122,14 +146,66 @@ SDL_AppResult SDL_AppEvent(void *, SDL_Event *evt) {
|
|||||||
return SDL_APP_CONTINUE;
|
return SDL_APP_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
GLuint vbo, program;
|
||||||
|
GLint aVertCoord, aTexCoord, uTex, uBackGround, uForeGround;
|
||||||
|
GLuint color, depth, stencil;
|
||||||
|
} fb;
|
||||||
|
|
||||||
SDL_AppResult SDL_AppIterate(void *) {
|
SDL_AppResult SDL_AppIterate(void *) {
|
||||||
glClearColor(0.5, 0.5, 0.5, 0.0);
|
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glViewport(0, 0, WINDOW_VIRTUAL, WINDOW_VIRTUAL);
|
||||||
|
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
struct crop c = {0, 0, 64, 64};
|
struct crop c = {0, 0, 64, 64};
|
||||||
batch_blit(-32, -32, &textures.at("turret"), &c);
|
batch_blit(-32, -32, &textures.at("turret"), &c);
|
||||||
batch_flush();
|
batch_flush();
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
if (square_pixels == false && integer_upscale == false) {
|
||||||
|
glViewport(0, 0, window_width, window_height);
|
||||||
|
} else if (square_pixels == false && integer_upscale == true) {
|
||||||
|
unsigned w = window_width / WINDOW_WIDTH * WINDOW_WIDTH, h = window_height / WINDOW_HEIGHT * WINDOW_HEIGHT;
|
||||||
|
glViewport((window_width - w) / 2, (window_height - h) / 2, w, h);
|
||||||
|
} else if (square_pixels == true && integer_upscale == false) {
|
||||||
|
static_assert(WINDOW_WIDTH / WINDOW_DENOM * WINDOW_DENOM == WINDOW_WIDTH);
|
||||||
|
static_assert(WINDOW_HEIGHT / WINDOW_DENOM * WINDOW_DENOM == WINDOW_HEIGHT);
|
||||||
|
unsigned w = window_width * WINDOW_DENOM / WINDOW_WIDTH, h = window_height * WINDOW_DENOM / WINDOW_HEIGHT;
|
||||||
|
unsigned s = w > h? h: w;
|
||||||
|
w = s * WINDOW_WIDTH / WINDOW_DENOM, h = s * WINDOW_HEIGHT / WINDOW_DENOM;
|
||||||
|
glViewport((window_width - w) / 2, (window_height - h) / 2, w, h);
|
||||||
|
} else if (square_pixels == true && integer_upscale == true) {
|
||||||
|
unsigned w = window_width / WINDOW_WIDTH, h = window_height / WINDOW_HEIGHT;
|
||||||
|
unsigned s = w > h? h: w;
|
||||||
|
w = s * WINDOW_WIDTH, h = s * WINDOW_HEIGHT;
|
||||||
|
glViewport((window_width - w) / 2, (window_height - h) / 2, w, h);
|
||||||
|
} else {
|
||||||
|
// how
|
||||||
|
}
|
||||||
|
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, fb.vbo);
|
||||||
|
glUseProgram(fb.program);
|
||||||
|
|
||||||
|
glVertexAttribPointer(fb.aVertCoord, 2, GL_FLOAT, GL_FALSE, sizeof (float [4]), (void *) 0);
|
||||||
|
glVertexAttribPointer(fb.aTexCoord, 2, GL_FLOAT, GL_TRUE, sizeof (float [4]), (void *) sizeof (float [2]));
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(fb.aVertCoord);
|
||||||
|
glEnableVertexAttribArray(fb.aTexCoord);
|
||||||
|
|
||||||
|
glUniform4f(fb.uForeGround, 1, 1, 0, 1);
|
||||||
|
glUniform4f(fb.uBackGround, 0, 0, 1, 1);
|
||||||
|
|
||||||
|
glUniform1i(fb.uTex, 0);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, fb.color);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
|
||||||
|
glDisableVertexAttribArray(fb.aVertCoord);
|
||||||
|
glDisableVertexAttribArray(fb.aTexCoord);
|
||||||
|
|
||||||
SDL_GL_SwapWindow(window);
|
SDL_GL_SwapWindow(window);
|
||||||
return SDL_APP_CONTINUE;
|
return SDL_APP_CONTINUE;
|
||||||
}
|
}
|
||||||
@ -137,3 +213,98 @@ SDL_AppResult SDL_AppIterate(void *) {
|
|||||||
void SDL_AppQuit(void *, SDL_AppResult) {
|
void SDL_AppQuit(void *, SDL_AppResult) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int framebuffer_init(void) {
|
||||||
|
fb.program = programs.at("up.trans");
|
||||||
|
glGenBuffers(1, &fb.vbo);
|
||||||
|
|
||||||
|
fb.aVertCoord = glGetAttribLocation(fb.program, "aVertCoord");
|
||||||
|
fb.aTexCoord = glGetAttribLocation(fb.program, "aTexCoord");
|
||||||
|
fb.uTex = glGetUniformLocation(fb.program, "uTex");
|
||||||
|
fb.uBackGround = glGetUniformLocation(fb.program, "uBackGround");
|
||||||
|
fb.uForeGround = glGetUniformLocation(fb.program, "uForeGround");
|
||||||
|
|
||||||
|
static_assert(WINDOW_WIDTH <= WINDOW_VIRTUAL);
|
||||||
|
static_assert(WINDOW_HEIGHT <= WINDOW_VIRTUAL);
|
||||||
|
const float horizontal = (WINDOW_VIRTUAL - WINDOW_WIDTH) / 2.0 / WINDOW_VIRTUAL;
|
||||||
|
const float vertical = (WINDOW_VIRTUAL - WINDOW_HEIGHT) / 2.0 / WINDOW_VIRTUAL;
|
||||||
|
const float vertices[] = {
|
||||||
|
-1, -1, 0 + horizontal, 0 + vertical,
|
||||||
|
+1, -1, 1 - horizontal, 0 + vertical,
|
||||||
|
-1, +1, 0 + horizontal, 1 - vertical,
|
||||||
|
+1, -1, 1 - horizontal, 0 + vertical,
|
||||||
|
-1, +1, 0 + horizontal, 1 - vertical,
|
||||||
|
+1, +1, 1 - horizontal, 1 - vertical,
|
||||||
|
};
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, fb.vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof (float [4]), vertices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
glGenFramebuffers(1, &framebuffer);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||||
|
|
||||||
|
glGenTextures(1, &fb.color);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, fb.color);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WINDOW_VIRTUAL, WINDOW_VIRTUAL, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.color, 0);
|
||||||
|
|
||||||
|
glGenRenderbuffers(1, &fb.depth);
|
||||||
|
glBindRenderbuffer(GL_RENDERBUFFER, fb.depth);
|
||||||
|
|
||||||
|
while (glGetError() != GL_NO_ERROR);
|
||||||
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, WINDOW_VIRTUAL, WINDOW_VIRTUAL);
|
||||||
|
|
||||||
|
// too much hope in humanity? dont worry!
|
||||||
|
// GLES2 does not support a depth+stencil format
|
||||||
|
// GLES2 has extensions for D24S8 format
|
||||||
|
// WEBGL supports a depth+stencil format
|
||||||
|
// the problem? the two are DIFFERENT depth+stencil formats!
|
||||||
|
if (glGetError() == GL_NO_ERROR) {
|
||||||
|
// depth24_stencil8 supported
|
||||||
|
fprintf(stderr, "info: fb: D24S8\n");
|
||||||
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb.depth);
|
||||||
|
} else {
|
||||||
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, WINDOW_VIRTUAL, WINDOW_VIRTUAL);
|
||||||
|
if (glGetError() == GL_NO_ERROR) {
|
||||||
|
// depth_stencil supported (??)
|
||||||
|
fprintf(stderr, "info: fb: DS?\n");
|
||||||
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb.depth);
|
||||||
|
} else {
|
||||||
|
// neither, fallback to separate depth and stencil
|
||||||
|
fprintf(stderr, "info: fb: D16 S8\n");
|
||||||
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, WINDOW_VIRTUAL, WINDOW_VIRTUAL);
|
||||||
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fb.depth);
|
||||||
|
|
||||||
|
glGenRenderbuffers(1, &fb.stencil);
|
||||||
|
glBindRenderbuffer(GL_RENDERBUFFER, fb.stencil);
|
||||||
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, WINDOW_VIRTUAL, WINDOW_VIRTUAL);
|
||||||
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb.stencil);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
|
||||||
|
case GL_FRAMEBUFFER_COMPLETE:
|
||||||
|
return 0;
|
||||||
|
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||||
|
fprintf(stderr, "error: fb: incomplete attachment\n");
|
||||||
|
return 1;
|
||||||
|
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||||
|
fprintf(stderr, "error: fb: missing attachment\n");
|
||||||
|
return 1;
|
||||||
|
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||||
|
fprintf(stderr, "error: fb: unsupported\n");
|
||||||
|
return 1;
|
||||||
|
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
|
||||||
|
fprintf(stderr, "error: fb: samples dont match\n");
|
||||||
|
return 1;
|
||||||
|
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
|
||||||
|
fprintf(stderr, "error: fb: layers\n");
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "error: fb: unknown error\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -7,9 +7,8 @@ varying vec2 vTexCoord;
|
|||||||
uniform sampler2D uTex;
|
uniform sampler2D uTex;
|
||||||
uniform vec4 uForeGround;
|
uniform vec4 uForeGround;
|
||||||
uniform vec4 uBackGround;
|
uniform vec4 uBackGround;
|
||||||
uniform vec4 uBackDrop;
|
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
float Color = texture2D(uTex, vTexCoord).r;
|
float Color = texture2D(uTex, vTexCoord).r;
|
||||||
gl_FragColor = mix(uBg, uFg, Color);
|
gl_FragColor = mix(uBackGround, uForeGround, Color);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,17 +7,11 @@ varying vec2 vTexCoord;
|
|||||||
uniform sampler2D uTex;
|
uniform sampler2D uTex;
|
||||||
uniform vec4 uForeGround;
|
uniform vec4 uForeGround;
|
||||||
uniform vec4 uBackGround;
|
uniform vec4 uBackGround;
|
||||||
uniform vec4 uBackDrop;
|
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
vec3 d = vec3(-1.0, 0.0, +1.0) / 256.0;
|
vec4 Color = texture2D(uTex, vTexCoord);
|
||||||
float Color = texture2D(uTex, vTexCoord).r;
|
if (Color.a < 0.5) {
|
||||||
float ColorL = texture2D(uTex, vTexCoord + d.xy).r;
|
|
||||||
float ColorR = texture2D(uTex, vTexCoord + dzy).r;
|
|
||||||
float ColorU = texture2D(uTex, vTexCoord + d.yx).r;
|
|
||||||
float ColorD = texture2D(uTex, vTexCoord + d.yz).r;
|
|
||||||
if (Color + ColorL + ColorR + ColorU + ColorD < 0.5) {
|
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
gl_FragColor = mix(uBg, uFg, Color);
|
gl_FragColor = mix(uBackGround, uForeGround, Color.r);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user