2022-05-06 04:00:36 +00:00
|
|
|
// Common
|
|
|
|
int32 requestedKeyboardOverlayImage = 0;
|
2015-10-30 12:18:44 +00:00
|
|
|
|
2022-05-06 04:00:36 +00:00
|
|
|
#ifndef QB64_GUI // begin stubs
|
|
|
|
|
|
|
|
// STUB: simulate generating a hardware surface
|
|
|
|
int32 new_hardware_img(int32 x, int32 y, uint32 *pixels, int32 flags) {
|
|
|
|
// create hardware img
|
|
|
|
int32 handle;
|
|
|
|
hardware_img_struct *hardware_img;
|
|
|
|
handle = list_add(hardware_img_handles);
|
2022-05-06 04:02:21 +00:00
|
|
|
hardware_img = (hardware_img_struct *)list_get(hardware_img_handles, handle);
|
2022-05-06 04:00:36 +00:00
|
|
|
hardware_img->w = x;
|
|
|
|
hardware_img->h = y;
|
|
|
|
hardware_img->dest_context_handle = 0;
|
|
|
|
hardware_img->depthbuffer_handle = 0;
|
|
|
|
hardware_img->pending_commands = 0;
|
|
|
|
hardware_img->remove = 0;
|
|
|
|
hardware_img->alpha_disabled = 0;
|
|
|
|
hardware_img->depthbuffer_mode = DEPTHBUFFER_MODE__ON;
|
|
|
|
hardware_img->valid = 1;
|
|
|
|
hardware_img->source_state.PO2_fix = PO2_FIX__OFF;
|
|
|
|
hardware_img->source_state.texture_wrap = TEXTURE_WRAP_MODE__UNKNOWN;
|
|
|
|
hardware_img->source_state.smooth_stretched = SMOOTH_MODE__UNKNOWN;
|
|
|
|
hardware_img->source_state.smooth_shrunk = SMOOTH_MODE__UNKNOWN;
|
|
|
|
if (flags & NEW_HARDWARE_IMG__BUFFER_CONTENT) {
|
|
|
|
hardware_img->texture_handle = 0;
|
|
|
|
if (flags & NEW_HARDWARE_IMG__DUPLICATE_PROVIDED_BUFFER) {
|
|
|
|
hardware_img->software_pixel_buffer = NULL;
|
|
|
|
} else {
|
|
|
|
free(pixels); // the buffer was meant to be consumed, so we just
|
|
|
|
// free it immediately
|
|
|
|
hardware_img->software_pixel_buffer = NULL;
|
2018-06-30 15:16:59 +00:00
|
|
|
}
|
2015-08-02 12:12:44 +00:00
|
|
|
}
|
2022-05-06 04:00:36 +00:00
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else // end stubs
|
|
|
|
|
|
|
|
int32 force_NPO2_fix = 0; // This should only be set to 1 for debugging QB64
|
|
|
|
|
|
|
|
uint32 *NPO2_buffer = (uint32 *)malloc(4);
|
|
|
|
int32 NPO2_buffer_size_in_pixels = 1;
|
|
|
|
|
|
|
|
uint32 *NPO2_texture_generate(int32 *px, int32 *py, uint32 *pixels) {
|
|
|
|
int32 ox = *px;
|
|
|
|
int32 oy = *py;
|
|
|
|
int32 nx = 1;
|
|
|
|
int32 ny = 1;
|
|
|
|
|
|
|
|
// assume not negative & not 0
|
|
|
|
while ((ox & 1) == 0) {
|
|
|
|
ox >>= 1;
|
|
|
|
nx <<= 1;
|
|
|
|
}
|
|
|
|
if (ox != 1) { // x is not a power of 2
|
|
|
|
while (ox != 0) {
|
|
|
|
ox >>= 1;
|
|
|
|
nx <<= 1;
|
2018-06-30 15:16:59 +00:00
|
|
|
}
|
2022-05-06 04:00:36 +00:00
|
|
|
nx << 1;
|
|
|
|
}
|
|
|
|
while ((oy & 1) == 0) {
|
|
|
|
oy >>= 1;
|
|
|
|
ny <<= 1;
|
|
|
|
}
|
|
|
|
if (oy != 1) { // y is not a power of 2
|
|
|
|
while (oy != 0) {
|
|
|
|
oy >>= 1;
|
|
|
|
ny <<= 1;
|
2018-06-30 15:16:59 +00:00
|
|
|
}
|
2022-05-06 04:00:36 +00:00
|
|
|
ny << 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// reset original values
|
|
|
|
ox = *px;
|
|
|
|
oy = *py;
|
|
|
|
|
|
|
|
if (nx == ox && ny == oy) { // no action required
|
|
|
|
return pixels;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32 size_in_pixels = nx * ny;
|
|
|
|
if (size_in_pixels > NPO2_buffer_size_in_pixels) {
|
|
|
|
NPO2_buffer = (uint32 *)realloc(NPO2_buffer, size_in_pixels * 4);
|
|
|
|
NPO2_buffer_size_in_pixels = size_in_pixels;
|
|
|
|
}
|
|
|
|
|
|
|
|
// copy source NPO2 rectangle into destination PO2 rectangle
|
|
|
|
if (nx == ox) { // can copy as a single block
|
|
|
|
memcpy(NPO2_buffer, pixels, ox * oy * 4);
|
|
|
|
} else {
|
|
|
|
uint32 *dst_pixel_offset = NPO2_buffer;
|
|
|
|
uint32 *src_pixel_offset = pixels;
|
|
|
|
while (oy--) {
|
|
|
|
memcpy(dst_pixel_offset, src_pixel_offset, ox * 4);
|
|
|
|
dst_pixel_offset += nx;
|
|
|
|
src_pixel_offset += ox;
|
2018-06-30 15:16:59 +00:00
|
|
|
}
|
2022-05-06 04:00:36 +00:00
|
|
|
oy = *py;
|
|
|
|
}
|
|
|
|
|
|
|
|
// tidy edges - extend the right-most column and bottom-most row to avoid
|
|
|
|
// pixel/color bleeding rhs column
|
|
|
|
if (ox != nx) {
|
|
|
|
for (int y = 0; y < oy; y++) {
|
|
|
|
NPO2_buffer[ox + nx * y] = NPO2_buffer[ox + nx * y - 1];
|
2018-06-30 15:16:59 +00:00
|
|
|
}
|
2015-08-02 12:12:44 +00:00
|
|
|
}
|
2022-05-06 04:00:36 +00:00
|
|
|
// bottom row + 1 pixel for corner
|
|
|
|
if (oy != ny) {
|
|
|
|
for (int x = 0; x < (ox + 1); x++) {
|
|
|
|
NPO2_buffer[nx * oy + x] = NPO2_buffer[nx * oy + x - nx];
|
|
|
|
}
|
2015-08-02 12:12:44 +00:00
|
|
|
}
|
2022-05-06 04:00:36 +00:00
|
|
|
|
|
|
|
// int maxtexsize;
|
|
|
|
// glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxtexsize);
|
|
|
|
// alert(maxtexsize);
|
|
|
|
|
|
|
|
// alert(nx);
|
|
|
|
// alert(ny);
|
|
|
|
|
|
|
|
*px = nx;
|
|
|
|
*py = ny;
|
|
|
|
|
|
|
|
return NPO2_buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32 new_texture_handle() {
|
|
|
|
GLuint texture = 0;
|
|
|
|
glGenTextures(1, &texture);
|
|
|
|
return (int32)texture;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32 new_hardware_img(int32 x, int32 y, uint32 *pixels, int32 flags) {
|
|
|
|
// note: non power-of-2 dimensioned textures are supported on modern 3D
|
|
|
|
// cards and
|
|
|
|
// even on some older cards, as long as mip-mapping is not being used
|
|
|
|
// therefore, no attempt is made to convert the non-power-of-2 SCREEN
|
|
|
|
// sizes via software to avoid the performance hit this would incur
|
|
|
|
// create hardware img
|
|
|
|
int32 handle;
|
|
|
|
hardware_img_struct *hardware_img;
|
|
|
|
handle = list_add(hardware_img_handles);
|
2022-05-06 04:02:21 +00:00
|
|
|
hardware_img = (hardware_img_struct *)list_get(hardware_img_handles, handle);
|
2022-05-06 04:00:36 +00:00
|
|
|
hardware_img->w = x;
|
|
|
|
hardware_img->h = y;
|
|
|
|
hardware_img->dest_context_handle = 0;
|
|
|
|
hardware_img->depthbuffer_handle = 0;
|
|
|
|
hardware_img->pending_commands = 0;
|
|
|
|
hardware_img->remove = 0;
|
|
|
|
hardware_img->alpha_disabled = 0;
|
|
|
|
hardware_img->depthbuffer_mode = DEPTHBUFFER_MODE__ON;
|
|
|
|
hardware_img->valid = 1;
|
|
|
|
hardware_img->source_state.PO2_fix = PO2_FIX__OFF;
|
|
|
|
hardware_img->source_state.texture_wrap = TEXTURE_WRAP_MODE__UNKNOWN;
|
|
|
|
hardware_img->source_state.smooth_stretched = SMOOTH_MODE__UNKNOWN;
|
|
|
|
hardware_img->source_state.smooth_shrunk = SMOOTH_MODE__UNKNOWN;
|
|
|
|
|
|
|
|
if (flags & NEW_HARDWARE_IMG__BUFFER_CONTENT) {
|
|
|
|
hardware_img->texture_handle = 0;
|
|
|
|
if (flags & NEW_HARDWARE_IMG__DUPLICATE_PROVIDED_BUFFER) {
|
|
|
|
hardware_img->software_pixel_buffer = (uint32 *)malloc(x * y * 4);
|
|
|
|
memcpy(hardware_img->software_pixel_buffer, pixels, x * y * 4);
|
|
|
|
} else {
|
|
|
|
hardware_img->software_pixel_buffer = pixels;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
hardware_img->software_pixel_buffer = NULL;
|
|
|
|
hardware_img->texture_handle = new_texture_handle();
|
|
|
|
glBindTexture(GL_TEXTURE_2D, hardware_img->texture_handle);
|
|
|
|
// non-power of 2 dimensions fallback support
|
|
|
|
static int glerrorcode;
|
|
|
|
glerrorcode = glGetError(); // clear any previous errors
|
|
|
|
if (force_NPO2_fix == 0)
|
2022-05-06 04:02:21 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
|
2022-05-06 04:00:36 +00:00
|
|
|
glerrorcode = glGetError();
|
|
|
|
if (glerrorcode != 0 || force_NPO2_fix == 1) {
|
|
|
|
int32 nx = x, ny = y;
|
|
|
|
uint32 *npixels = NPO2_texture_generate(&nx, &ny, pixels);
|
2022-05-06 04:02:21 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, nx, ny, 0, GL_BGRA, GL_UNSIGNED_BYTE, npixels);
|
2022-05-06 04:00:36 +00:00
|
|
|
hardware_img->source_state.PO2_fix = PO2_FIX__EXPANDED;
|
|
|
|
hardware_img->PO2_w = nx;
|
|
|
|
hardware_img->PO2_h = ny;
|
|
|
|
glerrorcode = glGetError();
|
|
|
|
if (glerrorcode) {
|
2022-05-06 04:02:21 +00:00
|
|
|
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, x, y, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
|
2022-05-06 04:00:36 +00:00
|
|
|
glerrorcode = glGetError();
|
|
|
|
if (glerrorcode) {
|
|
|
|
alert("gluBuild2DMipmaps failed");
|
|
|
|
alert(glerrorcode);
|
2018-06-30 15:16:59 +00:00
|
|
|
}
|
2022-05-06 04:00:36 +00:00
|
|
|
hardware_img->source_state.PO2_fix = PO2_FIX__MIPMAPPED;
|
|
|
|
hardware_img->PO2_w = x;
|
|
|
|
hardware_img->PO2_h = y;
|
2018-06-30 15:16:59 +00:00
|
|
|
}
|
|
|
|
}
|
2022-05-06 04:00:36 +00:00
|
|
|
set_render_source(INVALID_HARDWARE_HANDLE);
|
2015-08-02 12:12:44 +00:00
|
|
|
}
|
2022-05-06 04:00:36 +00:00
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
void hardware_img_buffer_to_texture(int32 handle) {
|
|
|
|
static hardware_img_struct *hardware_img;
|
2022-05-06 04:02:21 +00:00
|
|
|
hardware_img = (hardware_img_struct *)list_get(hardware_img_handles, handle);
|
2022-05-06 04:00:36 +00:00
|
|
|
if (hardware_img->texture_handle == 0) {
|
|
|
|
hardware_img->texture_handle = new_texture_handle();
|
|
|
|
glBindTexture(GL_TEXTURE_2D, hardware_img->texture_handle);
|
|
|
|
// non-power of 2 dimensions fallback support
|
|
|
|
static int glerrorcode;
|
|
|
|
glerrorcode = glGetError(); // clear any previous errors
|
|
|
|
if (force_NPO2_fix == 0)
|
2022-05-06 04:02:21 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, hardware_img->w, hardware_img->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, hardware_img->software_pixel_buffer);
|
2022-05-06 04:00:36 +00:00
|
|
|
glerrorcode = glGetError();
|
|
|
|
if (glerrorcode != 0 || force_NPO2_fix == 1) {
|
|
|
|
hardware_img->source_state.PO2_fix = PO2_FIX__EXPANDED;
|
|
|
|
int32 x = hardware_img->w;
|
|
|
|
int32 y = hardware_img->h;
|
2022-05-06 04:02:21 +00:00
|
|
|
uint32 *pixels = NPO2_texture_generate(&x, &y, hardware_img->software_pixel_buffer);
|
2022-05-06 04:00:36 +00:00
|
|
|
hardware_img->PO2_w = x;
|
|
|
|
hardware_img->PO2_h = y;
|
2022-05-06 04:02:21 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
|
2022-05-06 04:00:36 +00:00
|
|
|
glerrorcode = glGetError();
|
|
|
|
if (glerrorcode) {
|
2022-05-06 04:02:21 +00:00
|
|
|
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, hardware_img->w, hardware_img->h, GL_BGRA, GL_UNSIGNED_BYTE, hardware_img->software_pixel_buffer);
|
2022-05-06 04:00:36 +00:00
|
|
|
glerrorcode = glGetError();
|
|
|
|
if (glerrorcode) {
|
|
|
|
alert("gluBuild2DMipmaps failed");
|
|
|
|
alert(glerrorcode);
|
2018-06-30 15:16:59 +00:00
|
|
|
}
|
2022-05-06 04:00:36 +00:00
|
|
|
hardware_img->source_state.PO2_fix = PO2_FIX__MIPMAPPED;
|
|
|
|
hardware_img->PO2_w = hardware_img->w;
|
|
|
|
hardware_img->PO2_h = hardware_img->h;
|
2018-06-30 15:16:59 +00:00
|
|
|
}
|
|
|
|
}
|
2022-05-06 04:00:36 +00:00
|
|
|
free(hardware_img->software_pixel_buffer);
|
|
|
|
hardware_img->software_pixel_buffer = NULL; // 2015 critical bug fix
|
|
|
|
set_render_source(INVALID_HARDWARE_HANDLE);
|
2018-06-30 15:16:59 +00:00
|
|
|
}
|
2022-05-06 04:00:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void hardware_img_requires_depthbuffer(hardware_img_struct *hardware_img) {
|
|
|
|
if (hardware_img->depthbuffer_handle == 0) {
|
|
|
|
// inspiration...
|
|
|
|
// http://www.opengl.org/wiki/Framebuffer_Object_Examples#Color_texture.2C_Depth_texture
|
|
|
|
static GLuint depth_tex;
|
2022-05-06 04:02:21 +00:00
|
|
|
# ifndef QB64_GLES
|
2022-05-06 04:00:36 +00:00
|
|
|
glGenTextures(1, &depth_tex);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, depth_tex);
|
|
|
|
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);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
|
2022-05-06 04:02:21 +00:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
|
2022-05-06 04:00:36 +00:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
|
2022-05-06 04:02:21 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, hardware_img->w, hardware_img->h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
|
|
|
|
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depth_tex, 0 /*mipmap level*/);
|
|
|
|
# else
|
2022-05-06 04:00:36 +00:00
|
|
|
glGenRenderbuffers(1, &depth_tex);
|
|
|
|
glBindRenderbuffer(GL_RENDERBUFFER, depth_tex);
|
2022-05-06 04:02:21 +00:00
|
|
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, hardware_img->w, hardware_img->h);
|
|
|
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_tex);
|
|
|
|
# endif
|
2022-05-06 04:00:36 +00:00
|
|
|
// NULL means reserve texture memory, but texels are undefined
|
|
|
|
glClear(GL_DEPTH_BUFFER_BIT);
|
|
|
|
hardware_img->depthbuffer_handle = depth_tex;
|
|
|
|
set_render_source(INVALID_HARDWARE_HANDLE);
|
2018-06-30 15:16:59 +00:00
|
|
|
}
|
2022-05-06 04:00:36 +00:00
|
|
|
}
|
|
|
|
|
2015-08-02 12:12:44 +00:00
|
|
|
#endif
|