mirror of
https://github.com/QB64Official/qb64.git
synced 2024-08-31 11:10:18 +00:00
299 lines
9.4 KiB
C
299 lines
9.4 KiB
C
//Common
|
|
int32 requestedKeyboardOverlayImage=0;
|
|
|
|
#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);
|
|
hardware_img=(hardware_img_struct*)list_get(hardware_img_handles,handle);
|
|
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;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
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;
|
|
}
|
|
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;
|
|
}
|
|
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];
|
|
}
|
|
}
|
|
//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];
|
|
}
|
|
}
|
|
|
|
//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);
|
|
hardware_img=(hardware_img_struct*)list_get(hardware_img_handles,handle);
|
|
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);
|
|
#ifdef QB64_ANDROID
|
|
//BGRA->RGBA
|
|
uint32 *pos=(uint32*)hardware_img->software_pixel_buffer;
|
|
int32 numPixels=x*y;
|
|
uint32 col;
|
|
while(numPixels--){
|
|
col=*pos;
|
|
*pos++= (col&0xFF00FF00) | ((col & 0xFF0000) >> 16) | ((col & 0x0000FF) << 16);
|
|
}
|
|
#endif
|
|
}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) glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
|
|
glerrorcode=glGetError();
|
|
if (glerrorcode!=0||force_NPO2_fix==1){
|
|
int32 nx=x,ny=y;
|
|
uint32 *npixels=NPO2_texture_generate(&nx,&ny,pixels);
|
|
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, nx, ny, 0, GL_BGRA, GL_UNSIGNED_BYTE,npixels);
|
|
hardware_img->source_state.PO2_fix=PO2_FIX__EXPANDED;
|
|
hardware_img->PO2_w=nx;
|
|
hardware_img->PO2_h=ny;
|
|
glerrorcode=glGetError();
|
|
if (glerrorcode){
|
|
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, x, y, GL_BGRA, GL_UNSIGNED_BYTE, pixels );
|
|
glerrorcode=glGetError();
|
|
if (glerrorcode){
|
|
alert("gluBuild2DMipmaps failed");
|
|
alert(glerrorcode);
|
|
}
|
|
hardware_img->source_state.PO2_fix=PO2_FIX__MIPMAPPED;
|
|
hardware_img->PO2_w=x;
|
|
hardware_img->PO2_h=y;
|
|
}
|
|
}
|
|
set_render_source(INVALID_HARDWARE_HANDLE);
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
void hardware_img_buffer_to_texture(int32 handle){
|
|
static hardware_img_struct* hardware_img;
|
|
hardware_img=(hardware_img_struct*)list_get(hardware_img_handles,handle);
|
|
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) glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, hardware_img->w, hardware_img->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, hardware_img->software_pixel_buffer);
|
|
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;
|
|
uint32 *pixels=NPO2_texture_generate(&x,&y,hardware_img->software_pixel_buffer);
|
|
hardware_img->PO2_w=x;
|
|
hardware_img->PO2_h=y;
|
|
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_BGRA, GL_UNSIGNED_BYTE,pixels);
|
|
glerrorcode=glGetError();
|
|
if (glerrorcode){
|
|
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, hardware_img->w, hardware_img->h, GL_BGRA, GL_UNSIGNED_BYTE, hardware_img->software_pixel_buffer);
|
|
glerrorcode=glGetError();
|
|
if (glerrorcode){
|
|
alert("gluBuild2DMipmaps failed");
|
|
alert(glerrorcode);
|
|
}
|
|
hardware_img->source_state.PO2_fix=PO2_FIX__MIPMAPPED;
|
|
hardware_img->PO2_w=hardware_img->w;
|
|
hardware_img->PO2_h=hardware_img->h;
|
|
}
|
|
}
|
|
free(hardware_img->software_pixel_buffer);
|
|
hardware_img->software_pixel_buffer=NULL;//2015 critical bug fix
|
|
set_render_source(INVALID_HARDWARE_HANDLE);
|
|
}
|
|
}
|
|
|
|
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;
|
|
#ifndef QB64_GLES
|
|
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);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
|
|
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
|
|
glGenRenderbuffers(1, &depth_tex);
|
|
glBindRenderbuffer(GL_RENDERBUFFER, depth_tex);
|
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, hardware_img->w, hardware_img->h);
|
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_tex);
|
|
#endif
|
|
//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);
|
|
}
|
|
}
|
|
|
|
|
|
#endif
|