void OpenGL_Blitter::Blit(MDFN_Surface *src_surface, const MDFN_Rect *src_rect, const MDFN_Rect *dest_rect, const MDFN_Rect *original_src_rect, int InterlaceField, int UsingIP, int rotated) { MDFN_Rect tex_src_rect = *src_rect; float src_coords[4][2]; int dest_coords[4][2]; unsigned int tmpwidth; unsigned int tmpheight; uint32 *src_pixies; if(shader) { if(shader->ShaderNeedsBTIP()) UsingIP = VIDEOIP_BILINEAR; else UsingIP = VIDEOIP_OFF; } if(src_rect->w == 0 || src_rect->h == 0 || dest_rect->w == 0 || dest_rect->h == 0 || original_src_rect->w == 0 || original_src_rect->h == 0) { printf("[BUG] OpenGL blitting nothing? --- %d:%d %d:%d %d:%d\n", src_rect->w, src_rect->h, dest_rect->w, dest_rect->h, original_src_rect->w, original_src_rect->h); return; } src_pixies = src_surface->pixels + tex_src_rect.x + tex_src_rect.y * src_surface->pitchinpix; tex_src_rect.x = 0; tex_src_rect.y = 0; MakeDestCoords(dest_rect, dest_coords, rotated); p_glBindTexture(GL_TEXTURE_2D, textures[0]); p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, UsingIP ? GL_LINEAR : GL_NEAREST); p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, UsingIP ? GL_LINEAR : GL_NEAREST); if(SupportNPOT) { tmpwidth = src_rect->w; tmpheight = src_rect->h; if(tmpwidth != last_w || tmpheight != last_h) { p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tmpwidth, tmpheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); last_w = tmpwidth; last_h = tmpheight; } } else { bool ImageSizeChange = FALSE; tmpwidth = round_up_pow2(src_rect->w); tmpheight = round_up_pow2(src_rect->h); // If the required GL texture size has changed, resize the texture! :b if(tmpwidth != round_up_pow2(last_w) || tmpheight != round_up_pow2(last_h)) { p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tmpwidth, tmpheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); ImageSizeChange = TRUE; } // If the dimensions of our image stored in the texture have changed... if(src_rect->w != last_w || src_rect->h != last_h) ImageSizeChange = TRUE; // Only clean up if we're using pixel shaders and/or bilinear interpolation if(ImageSizeChange && (shader || UsingIP)) { uint32 neo_dbs = DummyBlackSize; if(src_rect->w != tmpwidth && neo_dbs < src_rect->h) neo_dbs = src_rect->h; if(src_rect->h != tmpheight && neo_dbs < src_rect->w) neo_dbs = src_rect->w; if(neo_dbs != DummyBlackSize) { //printf("Realloc: %d\n", neo_dbs); if(DummyBlack) MDFN_free(DummyBlack); if((DummyBlack = (uint32 *)MDFN_calloc(neo_dbs, sizeof(uint32), _("OpenGL dummy black texture data")))) DummyBlackSize = neo_dbs; else DummyBlackSize = 0; } //printf("Cleanup: %d %d, %d %d\n", src_rect->w, src_rect->h, tmpwidth, tmpheight); if(DummyBlack) // If memory allocation failed for some reason, don't clean the texture. :( { if(src_rect->w < tmpwidth) { //puts("X"); p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 1); p_glTexSubImage2D(GL_TEXTURE_2D, 0, src_rect->w, 0, 1, src_rect->h, GL_RGBA, GL_UNSIGNED_BYTE, DummyBlack); } if(src_rect->h < tmpheight) { //puts("Y"); p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_rect->w); p_glTexSubImage2D(GL_TEXTURE_2D, 0, 0, src_rect->h, src_rect->w, 1, GL_RGBA, GL_UNSIGNED_BYTE, DummyBlack); } } // end if(DummyBlack) } last_w = src_rect->w; last_h = src_rect->h; } MakeSourceCoords(&tex_src_rect, src_coords, tmpwidth, tmpheight); if(shader) shader->ShaderBegin(gl_screen_w, gl_screen_h, src_rect, dest_rect, tmpwidth, tmpheight, round((double)tmpwidth * original_src_rect->w / src_rect->w), round((double)tmpheight * original_src_rect->h / src_rect->h), rotated); p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_surface->pitchinpix); p_glTexSubImage2D(GL_TEXTURE_2D, 0, tex_src_rect.x, tex_src_rect.y, tex_src_rect.w, tex_src_rect.h, PixelFormat, PixelType, src_pixies); // // Draw texture // #ifdef MDFN_TRIANGLE_STRIP_TEST p_glBegin(GL_TRIANGLE_STRIP); #else p_glBegin(GL_QUADS); #endif if(UsingIP == VIDEOIP_LINEAR_X || UsingIP == VIDEOIP_LINEAR_Y) // Linear interpolation, on one axis { DrawLinearIP(UsingIP, rotated, &tex_src_rect, dest_rect, tmpwidth, tmpheight); } else // Regular bilinear or no interpolation. { DrawQuad(src_coords, dest_coords); } p_glEnd(); if(shader) shader->ShaderEnd(); if(using_scanlines) { float yif_offset = 0; int yh_shift = 0; if(using_scanlines < 0 && InterlaceField >= 0) { yif_offset = (float)InterlaceField / 512; yh_shift = 1; } p_glEnable(GL_BLEND); p_glBindTexture(GL_TEXTURE_2D, textures[1]); p_glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA); p_glBegin(GL_QUADS); p_glTexCoord2f(0.0f, yif_offset + (original_src_rect->h >> yh_shift) / 256.0f); // Bottom left of our picture. p_glVertex2f((signed)dest_coords[3][0], (signed)dest_coords[3][1]); p_glTexCoord2f(1.0f, yif_offset + (original_src_rect->h >> yh_shift) / 256.0f); // Bottom right of our picture. p_glVertex2f((signed)dest_coords[2][0], (signed)dest_coords[2][1]); p_glTexCoord2f(1.0f, yif_offset); // Top right of our picture. p_glVertex2f((signed)dest_coords[1][0], (signed)dest_coords[1][1]); p_glTexCoord2f(0.0f, yif_offset); // Top left of our picture. p_glVertex2f((signed)dest_coords[0][0], (signed)dest_coords[0][1]); p_glEnd(); p_glDisable(GL_BLEND); } //if(1) //{ // p_glAccum(GL_MULT, 0.99); // p_glAccum(GL_ACCUM, 1 - 0.99); // p_glAccum(GL_RETURN, 1.0); //} }
void BlitOpenGL(MDFN_Surface *src_surface, const MDFN_Rect *src_rect, const MDFN_Rect *dest_rect, const MDFN_Rect *original_src_rect) { MDFN_Rect tex_src_rect = *src_rect; float src_coords[4][2]; int dest_coords[4][2]; unsigned int tmpwidth; unsigned int tmpheight; uint32 *src_pixies; src_pixies = src_surface->pixels + tex_src_rect.x + tex_src_rect.y * src_surface->pitchinpix; tex_src_rect.x = 0; tex_src_rect.y = 0; MakeDestCoords(dest_rect, dest_coords); p_glBindTexture(GL_TEXTURE_2D, textures[0]); if(SupportNPOT) { tmpwidth = src_rect->w; tmpheight = src_rect->h; if(tmpwidth != last_w || tmpheight != last_h) { p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tmpwidth, tmpheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); last_w = tmpwidth; last_h = tmpheight; } } else { bool ImageSizeChange = FALSE; tmpwidth = round_up_pow2(src_rect->w); tmpheight = round_up_pow2(src_rect->h); // If the required GL texture size has changed, resize the texture! :b if(tmpwidth != round_up_pow2(last_w) || tmpheight != round_up_pow2(last_h)) { p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tmpwidth, tmpheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); ImageSizeChange = TRUE; } // If the dimensions of our image stored in the texture have changed... if(src_rect->w != last_w || src_rect->h != last_h) ImageSizeChange = TRUE; // Only clean up if we're using pixel shaders and/or bilinear interpolation if(ImageSizeChange && (UsingShader || UsingIP)) { uint32 neo_dbs = DummyBlackSize; if(src_rect->w != tmpwidth && neo_dbs < src_rect->h) neo_dbs = src_rect->h; if(src_rect->h != tmpheight && neo_dbs < src_rect->w) neo_dbs = src_rect->w; if(neo_dbs != DummyBlackSize) { //printf("Realloc: %d\n", neo_dbs); if(DummyBlack) MDFN_free(DummyBlack); if((DummyBlack = (uint32 *)MDFN_calloc(neo_dbs, sizeof(uint32), _("OpenGL dummy black texture data")))) DummyBlackSize = neo_dbs; else DummyBlackSize = 0; } //printf("Cleanup: %d %d, %d %d\n", src_rect->w, src_rect->h, tmpwidth, tmpheight); if(DummyBlack) // If memory allocation failed for some reason, don't clean the texture. :( { if(src_rect->w < tmpwidth) { //puts("X"); p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 1); p_glTexSubImage2D(GL_TEXTURE_2D, 0, src_rect->w, 0, 1, src_rect->h, GL_RGBA, GL_UNSIGNED_BYTE, DummyBlack); } if(src_rect->h < tmpheight) { //puts("Y"); p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_rect->w); p_glTexSubImage2D(GL_TEXTURE_2D, 0, 0, src_rect->h, src_rect->w, 1, GL_RGBA, GL_UNSIGNED_BYTE, DummyBlack); } } // end if(DummyBlack) } last_w = src_rect->w; last_h = src_rect->h; } MakeSourceCoords(&tex_src_rect, src_coords, tmpwidth, tmpheight); #if MDFN_WANT_OPENGL_SHADERS if(UsingShader) ShaderBegin(src_rect, dest_rect, tmpwidth, tmpheight); #endif p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_surface->pitchinpix); p_glTexSubImage2D(GL_TEXTURE_2D, 0, tex_src_rect.x, tex_src_rect.y, tex_src_rect.w, tex_src_rect.h, PixelFormat, PixelType, src_pixies); // // Draw texture // p_glBegin(GL_QUADS); if(UsingIP == VIDEOIP_LINEAR_X || UsingIP == VIDEOIP_LINEAR_Y) // Linear interpolation, on one axis { DrawLinearIP(UsingIP, CurGame->rotated, &tex_src_rect, dest_rect, tmpwidth, tmpheight); } else // Regular bilinear or no interpolation. { DrawQuad(src_coords, dest_coords); } p_glEnd(); #if MDFN_WANT_OPENGL_SHADERS if(UsingShader) ShaderEnd(); #endif if(using_scanlines) { p_glEnable(GL_BLEND); p_glBindTexture(GL_TEXTURE_2D, textures[1]); p_glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA); p_glBegin(GL_QUADS); p_glTexCoord2f(0.0f, 1.0f * original_src_rect->h / 256); // Bottom left of our picture. p_glVertex2f((signed)dest_coords[3][0], (signed)dest_coords[3][1]); p_glTexCoord2f(1.0f, 1.0f * original_src_rect->h / 256); // Bottom right of our picture. p_glVertex2f((signed)dest_coords[2][0], (signed)dest_coords[2][1]); p_glTexCoord2f(1.0f, 0.0f); // Top right of our picture. p_glVertex2f((signed)dest_coords[1][0], (signed)dest_coords[1][1]); p_glTexCoord2f(0.0f, 0.0f); // Top left of our picture. p_glVertex2f((signed)dest_coords[0][0], (signed)dest_coords[0][1]); p_glEnd(); p_glDisable(GL_BLEND); } //if(1) //{ // p_glAccum(GL_MULT, 0.99); // p_glAccum(GL_ACCUM, 1 - 0.99); // p_glAccum(GL_RETURN, 1.0); //} }