📄 gameswf_render_handler_ogl.cpp
字号:
// gameswf_render_handler_ogl.cpp -- Willem Kokke <willem@mindparity.com> 2003// This source code has been donated to the Public Domain. Do// whatever you want with it.// A gameswf::render_handler that uses SDL & OpenGL#include "gameswf.h"#include "gameswf_types.h"#include "base/image.h"#include "base/ogl.h"#include "base/utility.h"#include <string.h> // for memset()// choose the resampling method:// 1 = hardware (experimental, should be fast, somewhat buggy)// 2 = fast software bilinear (default)// 3 = use image::resample(), slow software resampling#define RESAMPLE_METHOD 2// Determines whether to generate mipmaps for smoother rendering of// minified textures. It actually tends to look OK to not use// mipmaps, though it is potentially a performance hit if you use big// textures.//// TODO: need to code mipmap LOD bias adjustment, to keep mipmaps from// looking too blurry. (Also applies to text rendering.)#define GENERATE_MIPMAPS 0// bitmap_info_ogl declarationstruct bitmap_info_ogl : public gameswf::bitmap_info{ bitmap_info_ogl(); bitmap_info_ogl(int width, int height, Uint8* data); bitmap_info_ogl(image::rgb* im); bitmap_info_ogl(image::rgba* im); ~bitmap_info_ogl() { if (m_texture_id > 0) { glDeleteTextures(1, (GLuint*) &m_texture_id); } }};struct render_handler_ogl : public gameswf::render_handler{ // Some renderer state. // Enable/disable antialiasing. bool m_enable_antialias; // Output size. float m_display_width; float m_display_height; gameswf::matrix m_current_matrix; gameswf::cxform m_current_cxform; void set_antialiased(bool enable) { m_enable_antialias = enable; } static void make_next_miplevel(int* width, int* height, Uint8* data) // Utility. Mutates *width, *height and *data to create the // next mip level. { assert(width); assert(height); assert(data); int new_w = *width >> 1; int new_h = *height >> 1; if (new_w < 1) new_w = 1; if (new_h < 1) new_h = 1; if (new_w * 2 != *width || new_h * 2 != *height) { // Image can't be shrunk along (at least) one // of its dimensions, so don't bother // resampling. Technically we should, but // it's pretty useless at this point. Just // change the image dimensions and leave the // existing pixels. } else { // Resample. Simple average 2x2 --> 1, in-place. for (int j = 0; j < new_h; j++) { Uint8* out = ((Uint8*) data) + j * new_w; Uint8* in = ((Uint8*) data) + (j << 1) * *width; for (int i = 0; i < new_w; i++) { int a; a = (*(in + 0) + *(in + 1) + *(in + 0 + *width) + *(in + 1 + *width)); *(out) = a >> 2; out++; in += 2; } } } // Munge parameters to reflect the shrunken image. *width = new_w; *height = new_h; } struct fill_style { enum mode { INVALID, COLOR, BITMAP_WRAP, BITMAP_CLAMP, LINEAR_GRADIENT, RADIAL_GRADIENT, }; mode m_mode; gameswf::rgba m_color; const gameswf::bitmap_info* m_bitmap_info; gameswf::matrix m_bitmap_matrix; gameswf::cxform m_bitmap_color_transform; bool m_has_nonzero_bitmap_additive_color; fill_style() : m_mode(INVALID), m_has_nonzero_bitmap_additive_color(false) { } void apply(/*const matrix& current_matrix*/) const // Push our style into OpenGL. { assert(m_mode != INVALID); if (m_mode == COLOR) { apply_color(m_color); glDisable(GL_TEXTURE_2D); } else if (m_mode == BITMAP_WRAP || m_mode == BITMAP_CLAMP) { assert(m_bitmap_info != NULL); apply_color(m_color); if (m_bitmap_info == NULL) { glDisable(GL_TEXTURE_2D); } else { // Set up the texture for rendering. { // Do the modulate part of the color // transform in the first pass. The // additive part, if any, needs to // happen in a second pass. glColor4f(m_bitmap_color_transform.m_[0][0], m_bitmap_color_transform.m_[1][0], m_bitmap_color_transform.m_[2][0], m_bitmap_color_transform.m_[3][0] ); } glBindTexture(GL_TEXTURE_2D, m_bitmap_info->m_texture_id); glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); if (m_mode == BITMAP_CLAMP) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else { assert(m_mode == BITMAP_WRAP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } // Set up the bitmap matrix for texgen. float inv_width = 1.0f / m_bitmap_info->m_original_width; float inv_height = 1.0f / m_bitmap_info->m_original_height; const gameswf::matrix& m = m_bitmap_matrix; glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); float p[4] = { 0, 0, 0, 0 }; p[0] = m.m_[0][0] * inv_width; p[1] = m.m_[0][1] * inv_width; p[3] = m.m_[0][2] * inv_width; glTexGenfv(GL_S, GL_OBJECT_PLANE, p); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); p[0] = m.m_[1][0] * inv_height; p[1] = m.m_[1][1] * inv_height; p[3] = m.m_[1][2] * inv_height; glTexGenfv(GL_T, GL_OBJECT_PLANE, p); } } } bool needs_second_pass() const // Return true if we need to do a second pass to make // a valid color. This is for cxforms with additive // parts; this is the simplest way (that we know of) // to implement an additive color with stock OpenGL. { if (m_mode == BITMAP_WRAP || m_mode == BITMAP_CLAMP) { return m_has_nonzero_bitmap_additive_color; } else { return false; } } void apply_second_pass() const // Set OpenGL state for a necessary second pass. { assert(needs_second_pass()); // The additive color also seems to be modulated by the texture. So, // maybe we can fake this in one pass using using the mean value of // the colors: c0*t+c1*t = ((c0+c1)/2) * t*2 // I don't know what the alpha component of the color is for. //glDisable(GL_TEXTURE_2D); glColor4f( m_bitmap_color_transform.m_[0][1] / 255.0f, m_bitmap_color_transform.m_[1][1] / 255.0f, m_bitmap_color_transform.m_[2][1] / 255.0f, m_bitmap_color_transform.m_[3][1] / 255.0f ); glBlendFunc(GL_ONE, GL_ONE); } void cleanup_second_pass() const { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } void disable() { m_mode = INVALID; } void set_color(gameswf::rgba color) { m_mode = COLOR; m_color = color; } void set_bitmap(const gameswf::bitmap_info* bi, const gameswf::matrix& m, bitmap_wrap_mode wm, const gameswf::cxform& color_transform) { m_mode = (wm == WRAP_REPEAT) ? BITMAP_WRAP : BITMAP_CLAMP; m_bitmap_info = bi; m_bitmap_matrix = m; m_bitmap_color_transform = color_transform; m_bitmap_color_transform.clamp(); m_color = gameswf::rgba( Uint8(m_bitmap_color_transform.m_[0][0] * 255.0f), Uint8(m_bitmap_color_transform.m_[1][0] * 255.0f), Uint8(m_bitmap_color_transform.m_[2][0] * 255.0f), Uint8(m_bitmap_color_transform.m_[3][0] * 255.0f)); if (m_bitmap_color_transform.m_[0][1] > 1.0f || m_bitmap_color_transform.m_[1][1] > 1.0f || m_bitmap_color_transform.m_[2][1] > 1.0f || m_bitmap_color_transform.m_[3][1] > 1.0f) { m_has_nonzero_bitmap_additive_color = true; } else { m_has_nonzero_bitmap_additive_color = false; } } bool is_valid() const { return m_mode != INVALID; } }; // Style state. enum style_index { LEFT_STYLE = 0, RIGHT_STYLE, LINE_STYLE, STYLE_COUNT }; fill_style m_current_styles[STYLE_COUNT]; gameswf::bitmap_info* create_bitmap_info_rgb(image::rgb* im) // Given an image, returns a pointer to a bitmap_info struct // that can later be passed to fill_styleX_bitmap(), to set a // bitmap fill style. { return new bitmap_info_ogl(im); } gameswf::bitmap_info* create_bitmap_info_rgba(image::rgba* im) // Given an image, returns a pointer to a bitmap_info struct // that can later be passed to fill_style_bitmap(), to set a // bitmap fill style. // // This version takes an image with an alpha channel. { return new bitmap_info_ogl(im); } gameswf::bitmap_info* create_bitmap_info_empty() // Create a placeholder bitmap_info. Used when // DO_NOT_LOAD_BITMAPS is set; then later on the host program // can use movie_definition::get_bitmap_info_count() and // movie_definition::get_bitmap_info() to stuff precomputed // textures into these bitmap infos. { return new bitmap_info_ogl; } gameswf::bitmap_info* create_bitmap_info_alpha(int w, int h, Uint8* data) // Create a bitmap_info so that it contains an alpha texture // with the given data (1 byte per texel). // // Munges *data (in order to make mipmaps)!! { return new bitmap_info_ogl(w, h, data); } void delete_bitmap_info(gameswf::bitmap_info* bi) // Delete the given bitmap info struct. { delete bi; } ~render_handler_ogl() { } void begin_display( gameswf::rgba background_color, int viewport_x0, int viewport_y0, int viewport_width, int viewport_height, float x0, float x1, float y0, float y1) // Set up to render a full frame from a movie and fills the // background. Sets up necessary transforms, to scale the // movie to fit within the given dimensions. Call // end_display() when you're done. // // The rectangle (viewport_x0, viewport_y0, viewport_x0 + // viewport_width, viewport_y0 + viewport_height) defines the // window coordinates taken up by the movie. // // The rectangle (x0, y0, x1, y1) defines the pixel // coordinates of the movie that correspond to the viewport // bounds. { m_display_width = fabsf(x1 - x0); m_display_height = fabsf(y1 - y0); glViewport(viewport_x0, viewport_y0, viewport_width, viewport_height); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glOrtho(x0, x1, y0, y1, -1, 1); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // GL_MODULATE glDisable(GL_TEXTURE_2D); // Clear the background, if background color has alpha > 0. if (background_color.m_a > 0) { // Draw a big quad. apply_color(background_color); glBegin(GL_QUADS);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -