#ifdef QB64_MACOSX #include #endif // trigger recompilation = 3 int32 displayorder_screen=1; int32 displayorder_hardware=2; int32 displayorder_glrender=3; int32 displayorder_hardware1=4; //sub__displayorder( 1 , 2 , 4 , 3 ); //id.specialformat = "[{_SCREEN|_HARDWARE|_HARDWARE1|_GLRENDER}[,{_SCREEN|_HARDWARE|_HARDWARE1|_GLRENDER}[,{_SCREEN|_HARDWARE|_HARDWARE1|_GLRENDER}[,{_SCREEN|_HARDWARE|_HARDWARE1|_GLRENDER}]]]]" void sub__displayorder(int32 method1,int32 method2,int32 method3,int32 method4){ //check no value has been used twice if (method1!=0) if (method1==method2||method1==method3||method1==method4){error(5); return;} if (method2!=0) if (method2==method1||method2==method3||method2==method4){error(5); return;} if (method3!=0) if (method3==method1||method3==method2||method3==method4){error(5); return;} if (method4!=0) if (method4==method1||method4==method2||method4==method3){error(5); return;} displayorder_screen=0; displayorder_hardware=0; displayorder_hardware1=0; displayorder_glrender=0; static int32 i,method; for (i=1;i<=4;i++){ if (i==1) method=method1; if (i==2) method=method2; if (i==3) method=method3; if (i==4) method=method4; if (method==1) displayorder_screen=i; if (method==2) displayorder_hardware=i; if (method==3) displayorder_hardware1=i; if (method==4) displayorder_glrender=i; } } //int32 gl_render_method=2; //1=behind, 2=ontop[default], 3=only void sub__glrender(int32 method){ //gl_render_method=method; if (method==1) sub__displayorder(4,1,2,3); if (method==2) sub__displayorder(1,2,4,3); if (method==3) sub__displayorder(4,0,0,0); } #ifndef QB64_GUI //begin stubs #else //end stubs void GLUT_RESHAPE_FUNC(int width, int height){ resize_event_x=width; resize_event_y=height; resize_event=-1; display_x_prev=display_x,display_y_prev=display_y; display_x=width; display_y=height; resize_pending=0; os_resize_event=1; set_view(VIEW_MODE__UNKNOWN); //***glutReshapeWindow(...) has no effect if called // within GLUT_RESHAPE_FUNC*** } //displaycall is the window of time to update our display #ifdef DEPENDENCY_GL extern void SUB__GL(); #endif #define GL_BGR 0x80E0 #define GL_BGRA 0x80E1 /* reference struct hardware_img_struct{ int32 w; int32 h; int32 texture_handle; int32 dest_context_handle;//used when rendering other images onto this image int32 temp;//if =1, delete immediately after use } list *hardware_img_handles=NULL; */ void free_hardware_img(int32 handle, int32 caller_id){ hardware_img_struct* hardware_img; hardware_img=(hardware_img_struct*)list_get(hardware_img_handles,handle); if (hardware_img==NULL){ alert("free_hardware_img: image does not exist"); } if (hardware_img->dest_context_handle){ GLuint context=(GLuint)hardware_img->dest_context_handle; glDeleteFramebuffersEXT(1, &context); } if (hardware_img->depthbuffer_handle){ GLuint depthbuffer_handle=(GLuint)hardware_img->depthbuffer_handle; glDeleteFramebuffersEXT(1, &depthbuffer_handle); } GLuint texture=(GLuint)hardware_img->texture_handle; glDeleteTextures(1, &texture); //test reasset of hardware+img //hardware_img=(hardware_img_struct*)list_get(hardware_img_handles,handle); //if (hardware_img==NULL) alert("free_hardware_img: image does not exist"); //if image has not been used, it may still have buffered pixel content if (hardware_img->software_pixel_buffer!=NULL){ free(hardware_img->software_pixel_buffer); } list_remove(hardware_img_handles,handle); } /* int32 new_hardware_frame(int32 x, int32 y){ int32 handle=new_hardware_frame_handle(); glBindTexture (GL_TEXTURE_2D, handle); glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); return handle; } void free_hardware_frame(int32 handle){ GLuint texture=(GLuint)handle; glDeleteTextures(1, &texture); } */ void prepare_environment_2d(){//called prior to rendering 2D content //precalculate critical dimensions, offsets & ratios static int32 can_scale;//can the screen be scaled on the window can_scale=0; static int32 need_square_pixels;//do we need square_pixels? if not we can stretch the screen need_square_pixels=0; environment_2d__screen_smooth=0; environment_2d__letterbox=0; if (full_screen>0){//in full screen //reference: ---int32 full_screen_set=-1;//0(windowed),1(stretched/closest),2(1:1)--- can_scale=1; if (full_screen==2) need_square_pixels=1; //note: 'letter-boxing' is only requred where the size of the window cannot be controlled, and the only place where this is the // case is full screen mode _SQUAREPIXELS environment_2d__screen_smooth=fullscreen_smooth; }else{//windowed if (resize_auto>0){//1=STRETCH,2=SMOOTH can_scale=1; if (resize_auto==2) environment_2d__screen_smooth=1; //note: screen will fix its aspect ratio automatically, so there is no need to enforce squarepixels } } if (environment_2d__screen_width==environment__window_width && environment_2d__screen_height==environment__window_height){ //screen size matches window environment_2d__screen_x1=0; environment_2d__screen_y1=0; environment_2d__screen_x2=environment_2d__screen_width-1; environment_2d__screen_y2=environment_2d__screen_height-1; environment_2d__screen_x_scale=1.0f; environment_2d__screen_y_scale=1.0f; environment_2d__screen_scaled_width=environment_2d__screen_width; environment_2d__screen_scaled_height=environment_2d__screen_height; environment_2d__screen_smooth=0;//no smoothing required }else{ //screen size does not match //calculate ratios static float window_ratio; static float screen_ratio; window_ratio=(float)environment__window_width/(float)environment__window_height; screen_ratio=(float)environment_2d__screen_width/(float)environment_2d__screen_height; if (can_scale==0){ //screen will appear in the top-left of the window with blank space on the bottom & right environment_2d__screen_x1=0; environment_2d__screen_y1=0; environment_2d__screen_x2=environment_2d__screen_width-1; environment_2d__screen_y2=environment_2d__screen_height-1; goto cant_scale; } if (need_square_pixels==0||(window_ratio==screen_ratio)){ //can stretch, no 'letter-box' required environment_2d__screen_x1=0; environment_2d__screen_y1=0; environment_2d__screen_x2=environment__window_width-1; environment_2d__screen_y2=environment__window_height-1; }else{ //'letter-box' required //this section needs revision static float x_scale,y_scale; static int32 x1,y1,x2,y2,z,x_limit,y_limit,x_offset,y_offset; //x_scale=(float)environment_2d__screen_width/(float)environment__window_width; //y_scale=(float)environment_2d__screen_height/(float)environment__window_height; //x_offset=0; y_offset=0; x1=0; y1=0; x2=environment__window_width-1; y2=environment__window_height-1; //x_limit=x2; y_limit=y2; if (window_ratio>screen_ratio){ //pad sides z=(float)environment__window_height*screen_ratio;//new width x1=environment__window_width/2-z/2; x2=x1+z-1; environment_2d__letterbox=1;//vertical black stripes required //x_offset=-x1; x_scale=(float)environment_2d__screen_width/(float)z; x_limit=z-1; }else{ //pad top/bottom z=(float)environment__window_width/screen_ratio;//new height y1=environment__window_height/2-z/2; y2=y1+z-1; environment_2d__letterbox=2;//horizontal black stripes required //y_offset=-y1; y_scale=(float)environment_2d__screen_height/(float)z; y_limit=z-1; } environment_2d__screen_x1=x1; environment_2d__screen_y1=y1; environment_2d__screen_x2=x2; environment_2d__screen_y2=y2; } cant_scale: environment_2d__screen_scaled_width=environment_2d__screen_x2-environment_2d__screen_x1+1; environment_2d__screen_scaled_height=environment_2d__screen_y2-environment_2d__screen_y1+1; environment_2d__screen_x_scale=(float)environment_2d__screen_scaled_width/(float)environment_2d__screen_width; environment_2d__screen_y_scale=(float)environment_2d__screen_scaled_height/(float)environment_2d__screen_height; } }//prepare_environment_2d int32 environment_2d__get_window_x1_coord(int32 x){ return qbr_float_to_long(((float)x)*environment_2d__screen_x_scale)+environment_2d__screen_x1; } int32 environment_2d__get_window_y1_coord(int32 y){ return qbr_float_to_long((float)y*environment_2d__screen_y_scale)+environment_2d__screen_y1; } int32 environment_2d__get_window_x2_coord(int32 x){ return qbr_float_to_long(((float)x+1.0f)*environment_2d__screen_x_scale-1.0f)+environment_2d__screen_x1; } int32 environment_2d__get_window_y2_coord(int32 y){ return qbr_float_to_long(((float)y+1.0f)*environment_2d__screen_y_scale-1.0f)+environment_2d__screen_y1; } struct environment_2d__window_rect_struct{ int32 x1; int32 y1; int32 x2; int32 y2; }; //this functions returns a constant rect dimensions to stop warping of image environment_2d__window_rect_struct tmp_rect; environment_2d__window_rect_struct *environment_2d__screen_to_window_rect(int32 x1,int32 y1,int32 x2,int32 y2){ tmp_rect.x1=qbr_float_to_long(((float)x1)*environment_2d__screen_x_scale)+environment_2d__screen_x1; tmp_rect.y1=qbr_float_to_long(((float)y1)*environment_2d__screen_y_scale)+environment_2d__screen_y1; static int32 w,h; w=abs(x2-x1)+1; h=abs(y2-y1)+1; //force round upwards to correct gaps when tiling w=((float)w)*environment_2d__screen_x_scale+0.99f; h=((float)h)*environment_2d__screen_y_scale+0.99f; tmp_rect.x2=w-1+tmp_rect.x1; tmp_rect.y2=h-1+tmp_rect.y1; //(code which doesn't support tiling) //tmp_rect.x2=qbr_float_to_long(((float)w)*environment_2d__screen_x_scale-1.0f)+tmp_rect.x1; //tmp_rect.y2=qbr_float_to_long(((float)h)*environment_2d__screen_y_scale-1.0f)+tmp_rect.y1; return &tmp_rect; } float *hardware_buffer_vertices=(float*)malloc(sizeof(float)*1); int32 hardware_buffer_vertices_max=1; int32 hardware_buffer_vertices_count=0; float *hardware_buffer_texcoords=(float*)malloc(sizeof(float)*1); int32 hardware_buffer_texcoords_max=1; int32 hardware_buffer_texcoords_count=0; void hardware_buffer_flush(){ if (hardware_buffer_vertices_count){ //ref: http://stackoverflow.com/questions/5009014/draw-square-with-opengl-es-for-ios if (hardware_buffer_vertices_count==hardware_buffer_texcoords_count){ glVertexPointer(2, GL_FLOAT, 2*sizeof(GL_FLOAT), hardware_buffer_vertices); //http://www.opengl.org/sdk/docs/man2/xhtml/glVertexPointer.xml glTexCoordPointer(2, GL_FLOAT, 2*sizeof(GL_FLOAT), hardware_buffer_texcoords); //http://www.opengl.org/sdk/docs/man2/xhtml/glTexCoordPointer.xml glDrawArrays(GL_TRIANGLES, 0, hardware_buffer_vertices_count/2);//start index, number of indexes }else{ glVertexPointer(3, GL_FLOAT, 3*sizeof(GL_FLOAT), hardware_buffer_vertices); //http://www.opengl.org/sdk/docs/man2/xhtml/glVertexPointer.xml glTexCoordPointer(2, GL_FLOAT, 2*sizeof(GL_FLOAT), hardware_buffer_texcoords); //http://www.opengl.org/sdk/docs/man2/xhtml/glTexCoordPointer.xml glDrawArrays(GL_TRIANGLES, 0, hardware_buffer_vertices_count/3);//start index, number of indexes } hardware_buffer_vertices_count=0; hardware_buffer_texcoords_count=0; } } void set_smooth(int32 new_mode_shrunk,int32 new_mode_stretched){ static int32 current_mode_shrunk; current_mode_shrunk=render_state.source->smooth_shrunk; static int32 current_mode_stretched; current_mode_stretched=render_state.source->smooth_stretched; if (new_mode_shrunk==current_mode_shrunk&&new_mode_stretched==current_mode_stretched) return; hardware_buffer_flush(); if (new_mode_shrunk==SMOOTH_MODE__DONT_SMOOTH){ if (render_state.source->PO2_fix==PO2_FIX__MIPMAPPED){ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); }else{ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);//Use _MAPTRIANGLE's _SMOOTHSHRUNK to apply linear filtering here } } if (new_mode_shrunk==SMOOTH_MODE__SMOOTH){ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } if (new_mode_stretched==SMOOTH_MODE__DONT_SMOOTH){ if (render_state.source->PO2_fix==PO2_FIX__MIPMAPPED){ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); }else{ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } } if (new_mode_stretched==SMOOTH_MODE__SMOOTH){ glTexParameterf ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } render_state.source->smooth_shrunk=new_mode_shrunk; render_state.source->smooth_stretched=new_mode_stretched; } void set_texture_wrap(int32 new_mode){ static int32 current_mode; current_mode=render_state.source->texture_wrap; if (new_mode==current_mode) return; hardware_buffer_flush(); if (new_mode==TEXTURE_WRAP_MODE__DONT_WRAP){ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } if (new_mode==TEXTURE_WRAP_MODE__WRAP){ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } render_state.source->texture_wrap=new_mode; } void set_alpha(int32 new_mode){ static int32 current_mode; current_mode=render_state.use_alpha; if (new_mode==current_mode) return; hardware_buffer_flush(); if (new_mode==ALPHA_MODE__DONT_BLEND){ glDisable(GL_BLEND); } if (new_mode==ALPHA_MODE__BLEND){ glEnable(GL_BLEND); if (framebufferobjects_supported){ #ifndef QB64_GLES //glBlendFuncSeparateEXT(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glBlendFuncSeparateEXT(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); #else glBlendFuncSeparateOES(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); #endif }else{ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } } render_state.use_alpha=new_mode; } void set_depthbuffer(int32 new_mode){ static int32 current_mode; current_mode=render_state.depthbuffer_mode; if (new_mode==current_mode) return; hardware_buffer_flush(); if (new_mode==DEPTHBUFFER_MODE__OFF){ glDisable(GL_DEPTH_TEST); glAlphaFunc(GL_ALWAYS, 0); } if (new_mode==DEPTHBUFFER_MODE__ON){ glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glAlphaFunc(GL_GREATER, 0.001); glEnable(GL_ALPHA_TEST); } if (new_mode==DEPTHBUFFER_MODE__LOCKED){ glEnable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); glAlphaFunc(GL_ALWAYS, 0); } render_state.depthbuffer_mode=new_mode; } void set_cull_mode(int32 new_mode){ static int32 current_mode; current_mode=render_state.cull_mode; if (new_mode==current_mode) return; hardware_buffer_flush(); if (new_mode==CULL_MODE__NONE){ glDisable(GL_CULL_FACE); } if (new_mode==CULL_MODE__CLOCKWISE_ONLY){ glFrontFace(GL_CW); if (current_mode!=CULL_MODE__ANTICLOCKWISE_ONLY) glEnable(GL_CULL_FACE); } if (new_mode==CULL_MODE__ANTICLOCKWISE_ONLY){ glFrontFace(GL_CCW); if (current_mode!=CULL_MODE__CLOCKWISE_ONLY) glEnable(GL_CULL_FACE); } render_state.cull_mode=new_mode; } void set_view(int32 new_mode){ //set view can only be called after the correct destination is chosen static int32 current_mode; current_mode=render_state.view_mode; if (new_mode==current_mode) return; hardware_buffer_flush(); if (new_mode==VIEW_MODE__RESET){ glDisable(GL_TEXTURE_2D); glDisable(GL_ALPHA_TEST); glDisable(GL_BLEND); glDisable(GL_COLOR_MATERIAL); glDisable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glDisable(GL_LIGHTING); glFrontFace(GL_CCW); glCullFace(GL_BACK); glDisable(GL_CULL_FACE); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glAlphaFunc(GL_ALWAYS, 0); if (framebufferobjects_supported) glBindFramebufferEXT(GL_FRAMEBUFFER, 0); glBindTexture (GL_TEXTURE_2D, 0); glClear(GL_DEPTH_BUFFER_BIT); glColor4f(1.f, 1.f, 1.f, 1.f); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //invalidate current states set_alpha(ALPHA_MODE__UNKNOWN); set_depthbuffer(DEPTHBUFFER_MODE__UNKNOWN); set_cull_mode(CULL_MODE__UNKNOWN); set_render_source(INVALID_HARDWARE_HANDLE); set_render_dest(INVALID_HARDWARE_HANDLE); new_mode=VIEW_MODE__UNKNOWN;//resets are performed before unknown operations are executed } if (new_mode==VIEW_MODE__2D){ if (current_mode!=VIEW_MODE__3D){ glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glDisable(GL_COLOR_MATERIAL); glDisable(GL_LIGHTING); set_alpha(ALPHA_MODE__BLEND); glEnable(GL_TEXTURE_2D); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glCullFace(GL_BACK); } if (render_state.dest_handle==0){ static int32 dst_w,dst_h; static int32 scale_factor=0; #ifdef QB64_MACOSX if (scale_factor==0) { // by default scale_factor should be 1, but in macOS Catalina (10.15.*) scale_factor must be setted in 2 // * in cases where the app is executed on system with Retina Display scale_factor = 1; // by default // lookup for retina/5k output from system_profiler (storing all outpun in stream) bool b_isRetina, b_is5k; FILE* consoleStream = popen("system_profiler SPDisplaysDataType", "r"); if (consoleStream) { char buffer[128]; while (!feof(consoleStream)) { if (fgets(buffer, 128, consoleStream) != NULL) { string szBuffer(buffer); if (!b_isRetina) b_isRetina = (szBuffer.rfind("Retina") != ULONG_MAX); if (!b_is5k) b_is5k = (szBuffer.rfind("5K") != ULONG_MAX); } } } pclose(consoleStream); if (b_isRetina || b_is5k) { // apply only factor = 2 if macOS is Catalina (11.15.* // kern.osrelease 19.*) char str[256]; size_t size = sizeof(str); int ret = sysctlbyname("kern.osrelease", str, &size, NULL, 0); string sz_osrelease(str); if (sz_osrelease.rfind("19.") == 0) scale_factor=2; } } #else scale_factor=1; #endif dst_w=environment__window_width; dst_h=environment__window_height; //alert(dst_w); //alert(dst_h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, dst_w, 0.0, dst_h, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glScalef(1, -1, 1);//flip vertically glTranslatef(0, -dst_h, 0);//move to new vertical position glViewport(0,0,dst_w * scale_factor,dst_h * scale_factor); }else{ static hardware_img_struct* hardware_img; hardware_img=(hardware_img_struct*)list_get(hardware_img_handles,render_state.dest_handle); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, hardware_img->w, 0, hardware_img->h); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glViewport(0,0,hardware_img->w,hardware_img->h); } } if (new_mode==VIEW_MODE__3D){ if (current_mode!=VIEW_MODE__2D){ glColor4f(1.f, 1.f, 1.f, 1.f); glDisable(GL_COLOR_MATERIAL); glDisable(GL_LIGHTING); set_alpha(ALPHA_MODE__BLEND); glEnable(GL_TEXTURE_2D); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glCullFace(GL_BACK); } if (render_state.dest_handle==0){ static int32 dst_w,dst_h; dst_w=environment__window_width; dst_h=environment__window_height; glViewport(0, 0, (GLsizei)dst_w, (GLsizei)dst_h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); //note: the max FOV is 90-degrees (this maximum applies to the longest screen dimension) float fov; if (environment_2d__screen_scaled_width>environment_2d__screen_scaled_height){ fov=90.0f*((float)environment__window_width/(float)environment_2d__screen_scaled_width); //convert fov from horizontal to vertical fov=fov*((float)dst_h/(float)dst_w); }else{ fov=90.0f*((float)environment__window_height/(float)environment_2d__screen_scaled_height); } gluPerspective(fov, (GLfloat)dst_w / (GLfloat)dst_h, 0.1, 10000.0); // Set the Field of view angle (in degrees), the aspect ratio of our window, and the new and far planes glMatrixMode(GL_MODELVIEW); glLoadIdentity(); }else{ static hardware_img_struct* hardware_img; hardware_img=(hardware_img_struct*)list_get(hardware_img_handles,render_state.dest_handle); static int32 dst_w,dst_h; dst_w=hardware_img->w; dst_h=hardware_img->h; glViewport(0, 0, (GLsizei)dst_w, (GLsizei)dst_h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glScalef (1.0, -1.0, 1.0); //note: the max FOV is 90-degrees (this maximum applies to the longest screen dimension) float fov; if (dst_w>dst_h){ fov=90.0f; //convert fov from horizontal to vertical fov=fov*((float)dst_h/(float)dst_w); }else{ fov=90.0f; } gluPerspective(fov, (GLfloat)dst_w / (GLfloat)dst_h, 0.1, 10000.0); // Set the Field of view angle (in degrees), the aspect ratio of our window, and the new and far planes glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //alert("3D rendering onto FBO not supported yet"); } } render_state.view_mode=new_mode; }//change_render_state void set_render_source(int32 new_handle){ if (new_handle==INVALID_HARDWARE_HANDLE){ hardware_buffer_flush(); render_state.source_handle=INVALID_HARDWARE_HANDLE; return; } int32 current_handle; current_handle=render_state.source_handle; if (current_handle==new_handle) return; hardware_buffer_flush(); hardware_img_struct* hardware_img; hardware_img=(hardware_img_struct*)list_get(hardware_img_handles,new_handle); if (hardware_img->texture_handle==0) hardware_img_buffer_to_texture(new_handle); glBindTexture (GL_TEXTURE_2D, hardware_img->texture_handle); render_state.source_handle=new_handle; render_state.source=&hardware_img->source_state; //note: some older systems require calling glTexParameterf after textures are rebound if (framebufferobjects_supported==0){ render_state.source->smooth_shrunk=SMOOTH_MODE__UNKNOWN; render_state.source->smooth_stretched=SMOOTH_MODE__UNKNOWN; } } void set_render_dest(int32 new_handle){ if (new_handle==INVALID_HARDWARE_HANDLE){ hardware_buffer_flush(); render_state.dest_handle=INVALID_HARDWARE_HANDLE; set_view(VIEW_MODE__UNKNOWN); return; } //0=primary surface static int32 current_handle; current_handle=render_state.dest_handle; if (new_handle==current_handle) return; hardware_buffer_flush(); set_view(VIEW_MODE__UNKNOWN); if (new_handle==0){ if (framebufferobjects_supported) glBindFramebufferEXT(GL_FRAMEBUFFER, 0); render_state.dest=&dest_render_state0; }else{ static hardware_img_struct* hardware_img; hardware_img=(hardware_img_struct*)list_get(hardware_img_handles,new_handle); //convert to regular texture first if necessary if (hardware_img->texture_handle==0) hardware_img_buffer_to_texture(new_handle); //does it have a dest context/FBO? if not create one if (hardware_img->dest_context_handle==0){ static GLuint framebuffer_handle; framebuffer_handle=0; glGenFramebuffersEXT(1, &framebuffer_handle); glBindFramebufferEXT(GL_FRAMEBUFFER, framebuffer_handle); hardware_img->dest_context_handle=framebuffer_handle; glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, hardware_img->texture_handle, 0); //glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //glClear(GL_COLOR_BUFFER_BIT); glColor4f(1.f, 1.f, 1.f, 1.f); set_render_source(INVALID_HARDWARE_HANDLE); }else{ glBindFramebufferEXT(GL_FRAMEBUFFER, hardware_img->dest_context_handle); } render_state.dest=&hardware_img->dest_state; } render_state.dest_handle=new_handle; } void hardware_img_put(int32 dst_x1,int32 dst_y1,int32 dst_x2,int32 dst_y2, int32 src_img,int32 dst_img, int32 src_x1,int32 src_y1,int32 src_x2,int32 src_y2, int32 use_alpha, int32 smooth ){ if (dst_img<0) dst_img=0;//both layers render to the primary context //ensure dst_x1/y1 represent top-left co-ordinate of destination static int32 swap_tmp; if (dst_x2x1; dst_y1=rect->y1; dst_x2=rect->x2; dst_y2=rect->y2; } set_render_source(src_img); static hardware_img_struct* src_hardware_img; static int32 src_h,src_w; src_hardware_img=(hardware_img_struct*)list_get(hardware_img_handles,src_img); src_h=src_hardware_img->h; src_w=src_hardware_img->w; if (smooth){ set_smooth(SMOOTH_MODE__SMOOTH,SMOOTH_MODE__SMOOTH); }else{ set_smooth(SMOOTH_MODE__DONT_SMOOTH,SMOOTH_MODE__DONT_SMOOTH); } if (use_alpha){ set_alpha(ALPHA_MODE__BLEND); }else{ set_alpha(ALPHA_MODE__DONT_BLEND); } set_depthbuffer(DEPTHBUFFER_MODE__OFF); set_cull_mode(CULL_MODE__NONE); set_texture_wrap(TEXTURE_WRAP_MODE__DONT_WRAP); //adjust for render (x2 & y2 need to be one greater than the destination offset) dst_x2++; dst_y2++; if (src_hardware_img->source_state.PO2_fix){ src_w=src_hardware_img->PO2_w; src_h=src_hardware_img->PO2_h; } //calc source texture co-ordinates static float x1f,y1f,x2f,y2f; if (src_x1<=src_x2){ x1f=((float)src_x1+0.01f)/(float)src_w; x2f=((float)src_x2+0.99f)/(float)src_w; }else{ x2f=((float)src_x2+0.01f)/(float)src_w; x1f=((float)src_x1+0.99f)/(float)src_w; } if (src_y1<=src_y2){ y1f=((float)src_y1+0.01f)/(float)src_h; y2f=((float)src_y2+0.99f)/(float)src_h; }else{ y2f=((float)src_y2+0.01f)/(float)src_h; y1f=((float)src_y1+0.99f)/(float)src_h; } //expand buffers if necessary if ((hardware_buffer_vertices_count+18)>hardware_buffer_vertices_max){ hardware_buffer_vertices_max=hardware_buffer_vertices_max*2+18; hardware_buffer_vertices=(float*)realloc(hardware_buffer_vertices,hardware_buffer_vertices_max*sizeof(float)); } if ((hardware_buffer_texcoords_count+12)>hardware_buffer_texcoords_max){ hardware_buffer_texcoords_max=hardware_buffer_texcoords_max*2+12; hardware_buffer_texcoords=(float*)realloc(hardware_buffer_texcoords,hardware_buffer_texcoords_max*sizeof(float)); } //clockwise hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_x1; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_y1; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_x2; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_y1; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_x1; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_y2; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=x1f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=y1f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=x2f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=y1f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=x1f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=y2f; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_x1; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_y2; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_x2; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_y1; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_x2; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_y2; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=x1f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=y2f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=x2f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=y1f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=x2f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=y2f; //hardware_buffer_flush(); //uncomment for debugging only } void hardware_img_tri2d(float dst_x1,float dst_y1,float dst_x2,float dst_y2,float dst_x3,float dst_y3, int32 src_img,int32 dst_img, float src_x1,float src_y1,float src_x2,float src_y2,float src_x3,float src_y3, int32 use_alpha, int32 smooth ){ if (dst_img<0) dst_img=0;//both layers render to the primary context set_render_dest(dst_img); set_view(VIEW_MODE__2D); if (dst_img){ static hardware_img_struct* dst_hardware_img; dst_hardware_img=(hardware_img_struct*)list_get(hardware_img_handles,dst_img); static int32 dst_w,dst_h; dst_w=dst_hardware_img->w; dst_h=dst_hardware_img->h; //SEAMLESS adjustments: //reduce texture co-ordinates (maintaining top-left) //(todo) //NON-SEAMLESS adjustments: //Extend rhs/bottom row to fill extra pixel space //calculate extents int32 rx1; int32 rx2; rx1=dst_x1; if (dst_x2rx2){ rx2=dst_x2; } if (dst_x3>rx2){ rx2=dst_x3; } float xr;//the multiplier for where we should be (1=no change) if (rx1==rx2){ xr=1.0f; }else{ xr=((float)rx2-(float)rx1+1.0)/((float)rx2-(float)rx1); } int32 ry1; int32 ry2; ry1=dst_y1; if (dst_y2ry2){ ry2=dst_y2; } if (dst_y3>ry2){ ry2=dst_y3; } float yr;//the multiplier for where we should be (1=no change) if (ry1==ry2){ yr=1.0f; }else{ yr=((float)ry2-(float)ry1+1.0f)/((float)ry2-(float)ry1); } //apply multipliers so right-most and bottom-most rows will be filled static int32 basex; basex=rx1; dst_x1=qbr_float_to_long( ((float)(dst_x1-rx1))*xr+(float)basex ); dst_x2=qbr_float_to_long( ((float)(dst_x2-rx1))*xr+(float)basex ); dst_x3=qbr_float_to_long( ((float)(dst_x3-rx1))*xr+(float)basex ); static int32 basey; basey=ry1; dst_y1=qbr_float_to_long( ((float)(dst_y1-ry1))*yr+(float)basey ); dst_y2=qbr_float_to_long( ((float)(dst_y2-ry1))*yr+(float)basey ); dst_y3=qbr_float_to_long( ((float)(dst_y3-ry1))*yr+(float)basey ); }else{ //dest is 0 static int32 dst_w,dst_h; dst_w=environment__window_width; dst_h=environment__window_height; //SEAMLESS adjustments: //reduce texture co-ordinates (maintaining top-left) //(todo) //NON-SEAMLESS adjustments: //Extend rhs/bottom row to fill extra pixel space //calculate extents int32 rx1; int32 rx2; rx1=dst_x1; if (dst_x2rx2){ rx2=dst_x2; } if (dst_x3>rx2){ rx2=dst_x3; } float xr;//the multiplier for where we should be (1=no change) if (rx1==rx2){ xr=1.0f; }else{ xr=((float)rx2-(float)rx1+1.0)/((float)rx2-(float)rx1); } int32 ry1; int32 ry2; ry1=dst_y1; if (dst_y2ry2){ ry2=dst_y2; } if (dst_y3>ry2){ ry2=dst_y3; } float yr;//the multiplier for where we should be (1=no change) if (ry1==ry2){ yr=1.0f; }else{ yr=((float)ry2-(float)ry1+1.0f)/((float)ry2-(float)ry1); } //apply multipliers so right-most and bottom-most rows will be filled static int32 basex; basex= qbr_float_to_long( ((float)(rx1))*environment_2d__screen_x_scale+(float)environment_2d__screen_x1 ); dst_x1= basex+ qbr_float_to_long( ((float)(dst_x1-rx1))*environment_2d__screen_x_scale*xr ); dst_x2= basex+ qbr_float_to_long( ((float)(dst_x2-rx1))*environment_2d__screen_x_scale*xr ); dst_x3= basex+ qbr_float_to_long( ((float)(dst_x3-rx1))*environment_2d__screen_x_scale*xr ); static int32 basey; basey= qbr_float_to_long( ((float)(ry1))*environment_2d__screen_y_scale+(float)environment_2d__screen_y1 ); dst_y1= basey+ qbr_float_to_long( ((float)(dst_y1-ry1))*environment_2d__screen_y_scale*yr ); dst_y2= basey+ qbr_float_to_long( ((float)(dst_y2-ry1))*environment_2d__screen_y_scale*yr ); dst_y3= basey+ qbr_float_to_long( ((float)(dst_y3-ry1))*environment_2d__screen_y_scale*yr ); } set_render_source(src_img); static hardware_img_struct* src_hardware_img; static int32 src_h,src_w; src_hardware_img=(hardware_img_struct*)list_get(hardware_img_handles,src_img); src_h=src_hardware_img->h; src_w=src_hardware_img->w; if (smooth==0){ set_smooth(SMOOTH_MODE__DONT_SMOOTH,SMOOTH_MODE__DONT_SMOOTH); } if (smooth==1){ set_smooth(SMOOTH_MODE__SMOOTH,SMOOTH_MODE__SMOOTH); } if (smooth==2){ set_smooth(SMOOTH_MODE__SMOOTH,SMOOTH_MODE__DONT_SMOOTH); } if (smooth==3){ set_smooth(SMOOTH_MODE__DONT_SMOOTH,SMOOTH_MODE__SMOOTH); } set_texture_wrap(TEXTURE_WRAP_MODE__WRAP); if (use_alpha){ set_alpha(ALPHA_MODE__BLEND); }else{ set_alpha(ALPHA_MODE__DONT_BLEND); } set_depthbuffer(DEPTHBUFFER_MODE__OFF); set_cull_mode(CULL_MODE__NONE); if (src_hardware_img->source_state.PO2_fix){ src_w=src_hardware_img->PO2_w; src_h=src_hardware_img->PO2_h; } //calc source texture co-ordinates static float x1f,y1f,x2f,y2f,x3f,y3f; x1f=((float)src_x1+0.5f)/(float)src_w; x2f=((float)src_x2+0.5f)/(float)src_w; x3f=((float)src_x3+0.5f)/(float)src_w; y1f=((float)src_y1+0.5f)/(float)src_h; y2f=((float)src_y2+0.5f)/(float)src_h; y3f=((float)src_y3+0.5f)/(float)src_h; //expand buffers if necessary if ((hardware_buffer_vertices_count+9)>hardware_buffer_vertices_max){ hardware_buffer_vertices_max=hardware_buffer_vertices_max*2+9; hardware_buffer_vertices=(float*)realloc(hardware_buffer_vertices,hardware_buffer_vertices_max*sizeof(float)); } if ((hardware_buffer_texcoords_count+6)>hardware_buffer_texcoords_max){ hardware_buffer_texcoords_max=hardware_buffer_texcoords_max*2+6; hardware_buffer_texcoords=(float*)realloc(hardware_buffer_texcoords,hardware_buffer_texcoords_max*sizeof(float)); } //clockwise hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_x1; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_y1; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_x2; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_y2; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_x3; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_y3; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=x1f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=y1f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=x2f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=y2f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=x3f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=y3f; //hardware_buffer_flush(); //uncomment for debugging only } void clear_depthbuffer(int32 dst_img){ hardware_buffer_flush(); if (dst_img<0) dst_img=0;//both layers render to the primary context set_render_dest(dst_img); if (dst_img>0){ hardware_img_requires_depthbuffer((hardware_img_struct*)list_get(hardware_img_handles,dst_img)); } glClear(GL_DEPTH_BUFFER_BIT); } void hardware_img_tri3d(float dst_x1,float dst_y1,float dst_z1,float dst_x2,float dst_y2,float dst_z2,float dst_x3,float dst_y3,float dst_z3, int32 src_img,int32 dst_img, float src_x1,float src_y1,float src_x2,float src_y2,float src_x3,float src_y3, int32 use_alpha, int32 smooth, int32 cull_mode, int32 depthbuffer_mode ){ if (dst_img<0) dst_img=0;//both layers render to the primary context set_render_dest(dst_img); set_view(VIEW_MODE__3D); if (dst_img){ static hardware_img_struct* dst_hardware_img; dst_hardware_img=(hardware_img_struct*)list_get(hardware_img_handles,dst_img); hardware_img_requires_depthbuffer(dst_hardware_img); }else{ //dest is 0 } set_render_source(src_img); static hardware_img_struct* src_hardware_img; static int32 src_h,src_w; src_hardware_img=(hardware_img_struct*)list_get(hardware_img_handles,src_img); src_h=src_hardware_img->h; src_w=src_hardware_img->w; if (smooth==0){ set_smooth(SMOOTH_MODE__DONT_SMOOTH,SMOOTH_MODE__DONT_SMOOTH); } if (smooth==1){ set_smooth(SMOOTH_MODE__SMOOTH,SMOOTH_MODE__SMOOTH); } if (smooth==2){ set_smooth(SMOOTH_MODE__SMOOTH,SMOOTH_MODE__DONT_SMOOTH); } if (smooth==3){ set_smooth(SMOOTH_MODE__DONT_SMOOTH,SMOOTH_MODE__SMOOTH); } set_texture_wrap(TEXTURE_WRAP_MODE__WRAP); if (use_alpha){ set_alpha(ALPHA_MODE__BLEND); }else{ set_alpha(ALPHA_MODE__DONT_BLEND); } set_depthbuffer(depthbuffer_mode); //on frame buffers the 3D perspective is flipped vertically reversing the cull direction if (dst_img>0){ if (cull_mode==CULL_MODE__CLOCKWISE_ONLY){ cull_mode=CULL_MODE__ANTICLOCKWISE_ONLY; }else{ if (cull_mode==CULL_MODE__ANTICLOCKWISE_ONLY) cull_mode=CULL_MODE__CLOCKWISE_ONLY; } } set_cull_mode(cull_mode); if (src_hardware_img->source_state.PO2_fix){ src_w=src_hardware_img->PO2_w; src_h=src_hardware_img->PO2_h; } //calc source texture co-ordinates static float x1f,y1f,x2f,y2f,x3f,y3f; x1f=((float)src_x1+0.5f)/(float)src_w; x2f=((float)src_x2+0.5f)/(float)src_w; x3f=((float)src_x3+0.5f)/(float)src_w; y1f=((float)src_y1+0.5f)/(float)src_h; y2f=((float)src_y2+0.5f)/(float)src_h; y3f=((float)src_y3+0.5f)/(float)src_h; //expand buffers if necessary if ((hardware_buffer_vertices_count+9)>hardware_buffer_vertices_max){ hardware_buffer_vertices_max=hardware_buffer_vertices_max*2+9; hardware_buffer_vertices=(float*)realloc(hardware_buffer_vertices,hardware_buffer_vertices_max*sizeof(float)); } if ((hardware_buffer_texcoords_count+6)>hardware_buffer_texcoords_max){ hardware_buffer_texcoords_max=hardware_buffer_texcoords_max*2+6; hardware_buffer_texcoords=(float*)realloc(hardware_buffer_texcoords,hardware_buffer_texcoords_max*sizeof(float)); } hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_x1; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_y1; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_z1; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_x2; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_y2; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_z2; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_x3; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_y3; hardware_buffer_vertices[hardware_buffer_vertices_count++]=dst_z3; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=x1f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=y1f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=x2f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=y2f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=x3f; hardware_buffer_texcoords[hardware_buffer_texcoords_count++]=y3f; //hardware_buffer_flush(); //uncomment for debugging only } static int32 software_screen_hardware_frame=0; static int32 in_GLUT_DISPLAY_REQUEST=0; void GLUT_DISPLAY_REQUEST(){ if (in_GLUT_DISPLAY_REQUEST){ return; } in_GLUT_DISPLAY_REQUEST=1; #ifdef QB64_MACOSX if (temp_window_title_set==1) { glutSetWindowTitle((char*)window_title); temp_window_title_set=0; } #endif //general use variables static int32 i,i2,i3; static int32 x,y,x2,y2; //determine which software frame to display static int32 last_i;//the last software frame displayed last_i=-1; for (i2=0;i2<=2;i2++){ if (display_frame[i2].state==DISPLAY_FRAME_STATE__DISPLAYING){ last_i=i2; } } i=-1; static int64 highest_order; highest_order=0; if (last_i!=-1) highest_order=display_frame[last_i].order;//avoid any frames below the current one for (i2=0;i2<=2;i2++){ if (display_frame[i2].state==DISPLAY_FRAME_STATE__READY&&display_frame[i2].order>highest_order){ highest_order=display_frame[i2].order; i=i2; } } if (i==-1) i=last_i; if (i==-1){ in_GLUT_DISPLAY_REQUEST=0; return;//no frames exist yet, so screen size cannot be determined, therefore no action possible } if (i!=last_i){ for (i2=0; i2<=2;i2++){ if (display_frame[i2].order1) use_alpha=1; //put the software screen hardware_img_put(0,0,environment_2d__screen_width-1,environment_2d__screen_height-1, software_screen_hardware_frame, 0, 0,0,f1->w-1,f1->h-1, use_alpha,environment_2d__screen_smooth); hardware_buffer_flush(); }//level==displayorder_screen if (level==displayorder_hardware||level==displayorder_hardware1){ static int32 dst; dst=0; if (level==displayorder_hardware1) dst=-1; static int32 command; command=0; static int32 caller_flag; caller_flag=0; if (first_hardware_layer_rendered==0){ if (first_hardware_command){ if (last_hardware_command_rendered){ if (rerender_prev_hardware_frame){ command=last_hardware_command_rendered; caller_flag=100; }else{ hardware_graphics_command_struct* last_hgc=(hardware_graphics_command_struct*)list_get(hardware_graphics_command_handles,last_hardware_command_rendered); if (last_hgc==NULL) alert("Rendering: Last HGC is NULL!"); command=last_hgc->next_command; caller_flag=200; } }else{ command=first_hardware_command; caller_flag=300; } //process/skip pending hardware puts before this frame's order value while (command){ hardware_graphics_command_struct* hgc=(hardware_graphics_command_struct*)list_get(hardware_graphics_command_handles,command); if (hgc->ordercommand==HARDWARE_GRAPHICS_COMMAND__FREEIMAGE){ free_hardware_img(hgc->src_img, 847002+caller_flag); } if (hgc->command==HARDWARE_GRAPHICS_COMMAND__PUTIMAGE){ if (hgc->dst_img>0){ //note: rendering to the old default surface is pointless, but renders onto maintained hardware images are still required hardware_img_put(hgc->dst_x1,hgc->dst_y1,hgc->dst_x2,hgc->dst_y2, hgc->src_img, hgc->dst_img, hgc->src_x1,hgc->src_y1,hgc->src_x2,hgc->src_y2, hgc->use_alpha,hgc->smooth); } } if (hgc->command==HARDWARE_GRAPHICS_COMMAND__MAPTRIANGLE){ if (hgc->dst_img>0){ //note: rendering to the old default surface is pointless, but renders onto maintained hardware images are still required hardware_img_tri2d(hgc->dst_x1,hgc->dst_y1,hgc->dst_x2,hgc->dst_y2,hgc->dst_x3,hgc->dst_y3, hgc->src_img, hgc->dst_img, hgc->src_x1,hgc->src_y1,hgc->src_x2,hgc->src_y2,hgc->src_x3,hgc->src_y3, hgc->use_alpha,hgc->smooth); } } if (hgc->command==HARDWARE_GRAPHICS_COMMAND__MAPTRIANGLE3D){ if (hgc->dst_img>0){ //note: rendering to the old default surface is pointless, but renders onto maintained hardware images are still required hardware_img_tri3d(hgc->dst_x1,hgc->dst_y1,hgc->dst_z1,hgc->dst_x2,hgc->dst_y2,hgc->dst_z2,hgc->dst_x3,hgc->dst_y3,hgc->dst_z3, hgc->src_img, hgc->dst_img, hgc->src_x1,hgc->src_y1,hgc->src_x2,hgc->src_y2,hgc->src_x3,hgc->src_y3, hgc->use_alpha,hgc->smooth,hgc->cull_mode,hgc->depthbuffer_mode); } } if (hgc->command==HARDWARE_GRAPHICS_COMMAND__CLEAR_DEPTHBUFFER){ if (hgc->dst_img>0){ //note: rendering to the old default surface is pointless, but renders onto maintained hardware images are still required clear_depthbuffer(hgc->dst_img); } } last_hardware_command_rendered=command; if (next_hardware_command_to_remove==0) next_hardware_command_to_remove=command; command=hgc->next_command; hgc->remove=1; }else{ goto found_command_from_current_order; } } found_command_from_current_order:; }//first_hardware_command first_hardware_layer_command=command; }else{ command=first_hardware_layer_command; } //process pending hardware puts for this frame's order value while (command){ hardware_graphics_command_struct* hgc=(hardware_graphics_command_struct*)list_get(hardware_graphics_command_handles,command); if (hgc==NULL){ hardware_graphics_command_struct* hgcx=(hardware_graphics_command_struct*)list_get(hardware_graphics_command_handles,next_hardware_command_to_remove); alert(order); alert(hgcx->order); alert(command); alert ("Renderer: Command does not exist."); } if (hgc->order==order){ if (first_command_prev_order==0) first_command_prev_order=command; if (hgc->command==HARDWARE_GRAPHICS_COMMAND__FREEIMAGE&&rerender_prev_hardware_frame==0&&first_hardware_layer_rendered==0){ free_hardware_img(hgc->src_img, 847003); } if (hgc->command==HARDWARE_GRAPHICS_COMMAND__PUTIMAGE){ if (rerender_prev_hardware_frame==0||hgc->dst_img<=0){ if ((hgc->dst_img>0&&first_hardware_layer_rendered==0)||hgc->dst_img==dst){ hardware_img_put(hgc->dst_x1,hgc->dst_y1,hgc->dst_x2,hgc->dst_y2, hgc->src_img, hgc->dst_img, hgc->src_x1,hgc->src_y1,hgc->src_x2,hgc->src_y2, hgc->use_alpha,hgc->smooth); } } } if (hgc->command==HARDWARE_GRAPHICS_COMMAND__MAPTRIANGLE){ if (rerender_prev_hardware_frame==0||hgc->dst_img<=0){ if ((hgc->dst_img>0&&first_hardware_layer_rendered==0)||hgc->dst_img==dst){ hardware_img_tri2d(hgc->dst_x1,hgc->dst_y1,hgc->dst_x2,hgc->dst_y2,hgc->dst_x3,hgc->dst_y3, hgc->src_img, hgc->dst_img, hgc->src_x1,hgc->src_y1,hgc->src_x2,hgc->src_y2,hgc->src_x3,hgc->src_y3, hgc->use_alpha,hgc->smooth); } } } if (hgc->command==HARDWARE_GRAPHICS_COMMAND__MAPTRIANGLE3D){ if (rerender_prev_hardware_frame==0||hgc->dst_img<=0){ if ((hgc->dst_img>0&&first_hardware_layer_rendered==0)||hgc->dst_img==dst){ hardware_img_tri3d(hgc->dst_x1,hgc->dst_y1,hgc->dst_z1,hgc->dst_x2,hgc->dst_y2,hgc->dst_z2,hgc->dst_x3,hgc->dst_y3,hgc->dst_z3, hgc->src_img, hgc->dst_img, hgc->src_x1,hgc->src_y1,hgc->src_x2,hgc->src_y2,hgc->src_x3,hgc->src_y3, hgc->use_alpha,hgc->smooth,hgc->cull_mode,hgc->depthbuffer_mode); } } } if (hgc->command==HARDWARE_GRAPHICS_COMMAND__CLEAR_DEPTHBUFFER){ if (rerender_prev_hardware_frame==0||hgc->dst_img<=0){ if ((hgc->dst_img>0&&first_hardware_layer_rendered==0)||hgc->dst_img==dst){ clear_depthbuffer(hgc->dst_img); } } } last_hardware_command_rendered=command; if (next_hardware_command_to_remove==0) next_hardware_command_to_remove=command;//!!!! should be prev to this command command=hgc->next_command; hgc->remove=1; }else{ goto finished_all_commands_for_current_frame; } } finished_all_commands_for_current_frame:; first_hardware_layer_rendered=1; hardware_buffer_flush(); }//level==displayorder_hardware||level==displayorder_hardware1 if (level==5){ if (environment_2d__letterbox){ //create a black texture (if not yet created) static uint32 black_pixel=0x00000000; static int32 black_texture=0; if (black_texture==0){ black_texture=new_hardware_img(1,1,&black_pixel,NULL); } if (environment_2d__letterbox==1){ //vertical stripes hardware_img_put(((float)-environment_2d__screen_x1)/environment_2d__screen_x_scale-1.0f,0,-1,environment_2d__screen_height-1, black_texture, 0, 0,0,0,0, 0,0); hardware_img_put(environment_2d__screen_width,0,(((float)-environment_2d__screen_x1)+(float)environment__window_width-1.0f)/environment_2d__screen_x_scale+1.0f,environment_2d__screen_height-1, black_texture, 0, 0,0,0,0, 0,0); }else{ //horizontal stripes hardware_img_put(0,((float)-environment_2d__screen_y1)/environment_2d__screen_y_scale-1.0f,environment_2d__screen_width-1,-1, black_texture, 0, 0,0,0,0, 0,0); hardware_img_put(0,environment_2d__screen_height,environment_2d__screen_width-1,(((float)-environment_2d__screen_y1)+(float)environment__window_height-1.0f)/environment_2d__screen_y_scale+1.0f, black_texture, 0, 0,0,0,0, 0,0); } hardware_buffer_flush(); }//letterbox }//level==5 }//level!=0 }//level loop if (requestedKeyboardOverlayImage){ int32 src=requestedKeyboardOverlayImage-HARDWARE_IMG_HANDLE_OFFSET; hardware_img_struct* src_hardware_img; src_hardware_img=(hardware_img_struct*)list_get(hardware_img_handles,src); /* hardware_img_put(0,0,src_hardware_img->w-1,src_hardware_img->h-1, src, 0, 0,0,src_hardware_img->w-1,src_hardware_img->h-1, 1,0); */ hardware_img_put(0,0,environment_2d__screen_width-1,environment_2d__screen_height-1, src, 0, 0,0,src_hardware_img->w-1,src_hardware_img->h-1, 1,0); hardware_buffer_flush(); } last_rendered_hardware_display_frame_order=last_hardware_display_frame_order; if (suspend_program){ //Otherwise skipped SUB__GL content becomes "invisible" //... }else{ glutSwapBuffers(); } in_GLUT_DISPLAY_REQUEST=0; }//GLUT_DISPLAY_REQUEST void GLUT_MouseButton_Up(int button,int x,int y){ #ifdef QB64_GLUT int32 i; int32 handle; handle=mouse_message_queue_first; mouse_message_queue_struct *queue=(mouse_message_queue_struct*)list_get(mouse_message_queue_handles,handle); i=queue->last+1; if (i>queue->lastIndex) i=0; if (i==queue->current){ int32 nextIndex=queue->last+1; if (nextIndex>queue->lastIndex) nextIndex=0; queue->current=nextIndex; } queue->queue[i].x=x; queue->queue[i].y=y; queue->queue[i].movementx=0; queue->queue[i].movementy=0; queue->queue[i].buttons=queue->queue[queue->last].buttons; if (queue->queue[i].buttons&(1<<(button-1))) queue->queue[i].buttons^=(1<<(button-1)); queue->last=i; if (device_last){//core devices required? if ((button>=1)&&(button<=3)){ button--; static device_struct *d; d=&devices[2];//mouse int32 eventIndex=createDeviceEvent(d); setDeviceEventButtonValue(d,eventIndex,button,0); commitDeviceEvent(d); }//valid range }//core devices required #endif } void GLUT_MouseButton_Down(int button,int x,int y){ #ifdef QB64_GLUT int32 i; int32 handle; handle=mouse_message_queue_first; mouse_message_queue_struct *queue=(mouse_message_queue_struct*)list_get(mouse_message_queue_handles,handle); i=queue->last+1; if (i>queue->lastIndex) i=0; if (i==queue->current){ int32 nextIndex=queue->last+1; if (nextIndex>queue->lastIndex) nextIndex=0; queue->current=nextIndex; } queue->queue[i].x=x; queue->queue[i].y=y; queue->queue[i].movementx=0; queue->queue[i].movementy=0; queue->queue[i].buttons=queue->queue[queue->last].buttons; queue->queue[i].buttons|=(1<<(button-1)); queue->last=i; if (device_last){//core devices required? if ((button>=1)&&(button<=3)){ button--; static device_struct *d; d=&devices[2];//mouse int32 eventIndex=createDeviceEvent(d); setDeviceEventButtonValue(d,eventIndex,button,1); commitDeviceEvent(d); //1-3 }else{ //not 1-3 //mouse wheel? if ((button>=4)&&(button<=5)){ static float f; if (button==4) f=-1; else f=1; static device_struct *d; d=&devices[2];//mouse int32 eventIndex=createDeviceEvent(d); setDeviceEventWheelValue(d,eventIndex,2,f); commitDeviceEvent(d); eventIndex=createDeviceEvent(d); setDeviceEventWheelValue(d,eventIndex,2,0); commitDeviceEvent(d); }//4-5 }//not 1-3 }//core devices required #endif } void GLUT_MOUSE_FUNC(int glut_button,int state,int x,int y){ #ifdef QB64_GLUT if (state==GLUT_DOWN) GLUT_MouseButton_Down(glut_button + 1,x,y); if (state==GLUT_UP) GLUT_MouseButton_Up(glut_button + 1,x,y); #endif } void GLUT_MOTION_FUNC(int x, int y){ int32 i, last_i; int32 handle; int32 xrel, yrel; handle=mouse_message_queue_first; mouse_message_queue_struct *queue=(mouse_message_queue_struct*)list_get(mouse_message_queue_handles,handle); //message #1 last_i=queue->last; i=queue->last+1; if (i>queue->lastIndex) i=0; //wrap around if (i==queue->current){ int32 nextIndex=queue->last+1; if (nextIndex>queue->lastIndex) nextIndex=0; queue->current=nextIndex; } #ifdef QB64_WINDOWS // Windows calculates relative movement by intercepting WM_INPUT events instead xrel = 0; yrel = 0; #else xrel = x - queue->queue[queue->last].x; yrel = y - queue->queue[queue->last].y; #endif queue->queue[i].x=x; queue->queue[i].y=y; queue->queue[i].movementx=xrel; queue->queue[i].movementy=yrel; queue->queue[i].buttons=queue->queue[last_i].buttons; queue->last=i; //message #2 (clears movement values to avoid confusion) last_i=queue->last; i=queue->last+1; if (i>queue->lastIndex) i=0; if (i==queue->current){ int32 nextIndex=queue->last+1; if (nextIndex>queue->lastIndex) nextIndex=0; queue->current=nextIndex; } queue->queue[i].x=x; queue->queue[i].y=y; queue->queue[i].movementx=0; queue->queue[i].movementy=0; queue->queue[i].buttons=queue->queue[last_i].buttons; queue->last=i; if (device_last){//core devices required? if (!device_mouse_relative){ static device_struct *d; d=&devices[2];//mouse int32 eventIndex=createDeviceEvent(d); static float fx,fy; static int32 z; fx=x; fx-=x_offset; z=x_monitor-x_offset*2; if (fx<0) fx=0; if (fx>=z) fx=z-1; fx=fx/(float)(z-1);//0 to 1 fx*=2.0;//0 to 2 fx-=1.0;//-1 to 1 fy=y; fy-=y_offset; z=y_monitor-y_offset*2; if (fy<0) fy=0; if (fy>=z) fy=z-1; fy=fy/(float)(z-1);//0 to 1 fy*=2.0;//0 to 2 fy-=1.0;//-1 to 1 setDeviceEventAxisValue(d,eventIndex,0,fx); setDeviceEventAxisValue(d,eventIndex,1,fy); commitDeviceEvent(d); }else{ static device_struct *d; d=&devices[2];//mouse int32 eventIndex=createDeviceEvent(d); static float fx,fy; static int32 z; fx=xrel; fy=yrel; setDeviceEventWheelValue(d,eventIndex,0,fx); setDeviceEventWheelValue(d,eventIndex,1,fy); commitDeviceEvent(d); eventIndex=createDeviceEvent(d); fx=0; fy=0; setDeviceEventWheelValue(d,eventIndex,0,fx); setDeviceEventWheelValue(d,eventIndex,1,fy); commitDeviceEvent(d); } }//core devices required } void GLUT_PASSIVEMOTION_FUNC(int x, int y){ GLUT_MOTION_FUNC(x,y); } void GLUT_MOUSEWHEEL_FUNC(int wheel, int direction, int x, int y){ #ifdef QB64_GLUT //Note: freeglut specific, limited documentation existed so the following research was done: // qbs_print(qbs_str(wheel),NULL); <-- was always 0 [could 1 indicate horizontal wheel?] // qbs_print(qbs_str(direction),NULL); <-- 1(up) or -1(down) // qbs_print(qbs_str(x),NULL); <--mouse x,y co-ordinates // qbs_print(qbs_str(y),1); < if (direction>0){GLUT_MouseButton_Down(4,x,y); GLUT_MouseButton_Up(4,x,y);} if (direction<0){GLUT_MouseButton_Down(5,x,y); GLUT_MouseButton_Up(5,x,y);} #endif } #endif