//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;yw=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) 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