/* * Overreact - Mr. 4th Dimention * Allen Webster * 03.21.2015 (mm.dd.yyyy) * * Win32 Rendering System Layer. */ #define SIG_STARTUP(name) void(name)(Win32RenderingVars *render_vars) #define SIG_SHUTDOWN(name) void(name)(Win32RenderingVars *render_vars) #define SIG_REDRAW(name) void(name)(Win32RenderingVars *render_vars) #define SIG_SET_SIZE(name) void(name)(Win32RenderingVars *render_vars, i32 port_width, i32 port_height, i32 view_width, i32 view_height) #define SIG_GET_RENDER_TARGET(name) Game_Render_Target(name)(Win32RenderingVars *render_vars) #if RENDER_MODE == SOFTWARE struct Win32RenderingVars{ HDC hdc; BITMAPINFO bmp_info; i32 width, height, pitch; i32 pixel_data_size; void *pixel_data; }; internal SIG_STARTUP(render_startup){} internal SIG_SHUTDOWN(render_shutdown){} internal SIG_REDRAW(render_redraw_screen){ render_vars->bmp_info.bmiHeader.biHeight = -render_vars->bmp_info.bmiHeader.biHeight; SetDIBitsToDevice(render_vars->hdc, 0, 0, render_vars->width, render_vars->height, 0, 0, 0, render_vars->height, render_vars->pixel_data, &render_vars->bmp_info, DIB_RGB_COLORS); render_vars->bmp_info.bmiHeader.biHeight = -render_vars->bmp_info.bmiHeader.biHeight; } // TODO(allen): This version ignores view / port ratio. It simply resize // to the dimensions of the port and the game will render in the top // left leaving the rest of the window ignored. Either implement // software stretching, or at least center the view like the original Push. internal SIG_SET_SIZE(render_set_screen_size){ render_vars->width = port_width; render_vars->height = port_height; render_vars->pitch = port_width*4; render_vars->bmp_info = {}; BITMAPINFOHEADER bmi_header = {}; bmi_header.biSize = sizeof(BITMAPINFOHEADER); bmi_header.biWidth = render_vars->width; bmi_header.biHeight = render_vars->height; bmi_header.biPlanes = 1; bmi_header.biBitCount = 32; bmi_header.biCompression = BI_RGB; render_vars->bmp_info.bmiHeader = bmi_header; // TODO(allen): Bulletproof this. i32 new_size = port_height*port_width*4; if (new_size > render_vars->pixel_data_size){ if (render_vars->pixel_data){ VirtualFree(render_vars->pixel_data, 0, MEM_RELEASE); } render_vars->pixel_data_size = new_size; render_vars->pixel_data = VirtualAlloc(0, height*width*4, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (!render_vars->pixel_data){ WINERROR("Failed to setup window pixel memory"); } } } SIG_GET_RENDER_TARGET(render_get_render_target){ Game_Render_Target render; render.pixels = (u8*)render_vars->pixel_data; render.width = render_vars->width; render.height = render_vars->height; render.pitch = render_vars->pitch; return render; } #elif RENDER_MODE == OPENGL struct Win32RenderingVars{ HDC hdc; HGLRC context; i32 width, height; }; internal SIG_STARTUP(render_startup){ int nPixelFormat; static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), //size of structure 1, //default version PFD_DRAW_TO_WINDOW | //window drawing support PFD_SUPPORT_OPENGL | //opengl support PFD_DOUBLEBUFFER, //double buffering support PFD_TYPE_RGBA, //RGBA color mode 32, //32 bit color mode 0, 0, 0, 0, 0, 0, //ignore color bits 0, //no alpha buffer 0, //ignore shift bit 0, //no accumulation buffer 0, 0, 0, 0, //ignore accumulation bits 16, //16 bit z-buffer size 0, //no stencil buffer 0, //no aux buffer PFD_MAIN_PLANE, //main drawing plane 0, //reserved 0, 0, 0 }; //layer masks ignored nPixelFormat = ChoosePixelFormat(render_vars->hdc, &pfd); SetPixelFormat(render_vars->hdc, nPixelFormat, &pfd); render_vars->context = wglCreateContext(render_vars->hdc); wglMakeCurrent(render_vars->hdc, render_vars->context); glShadeModel(GL_SMOOTH); glEnable(GL_TEXTURE_2D); //glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GLenum error; error = glGetError(); error = error; } internal SIG_SHUTDOWN(render_shutdown){ wglMakeCurrent(render_vars->hdc, 0); wglDeleteContext(render_vars->context); } internal SIG_REDRAW(render_redraw_screen){ glFlush(); SwapBuffers(render_vars->hdc); } // NOTE(allen): This changes the aspect ratio of the view to perfectly // fill the window. The height is untouched, the width is the only part // of the view that is effected. internal SIG_SET_SIZE(render_set_screen_size){ render_vars->height = view_height; render_vars->width = (i32)((port_width / ((real32)port_height)) * view_height); glViewport(0, 0, port_width, port_height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.f, render_vars->width, view_height, 0.f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } // NOTE(allen): This maintains a fixed aspect ratio and // puts the game port in the center, expecting the game to // add bars #if 0 internal SIG_SET_SIZE(render_set_screen_size){ render_vars->width = view_width; render_vars->height = view_height; real32 ratio_width, ratio_height; ratio_width = (real32)(port_width) / view_width; ratio_height = (real32)(port_height) / view_height; i32 start_x, start_y; if (ratio_width > ratio_height){ ratio_width = ratio_height; start_y = 0; start_x = (port_width - (ratio_width*view_width))/2; } else{ ratio_height = ratio_width; start_x = 0; start_y = (port_height - (ratio_height*view_height))/2; } glViewport(start_x, start_y, ratio_width*view_width, ratio_height*view_height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.f, view_width, view_height, 0.f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } #endif SIG_GET_RENDER_TARGET(render_get_render_target){ Game_Render_Target render = {}; render.width = render_vars->width; render.height = render_vars->height; return render; } #endif