From b3a696aecdf2fa1e981d18cbbc5d1af688cee50c Mon Sep 17 00:00:00 2001 From: Taylor Richards Date: Sun, 29 May 2016 23:14:23 -0400 Subject: [PATCH] first pass at OpenGL ES 2 support --- include/2d.h | 1 + include/CMakeLists.txt | 1 + include/grgl1.h | 32 +- include/grgl2.h | 65 +++ include/gropengl.h | 2 - include/gropenglinternal.h | 36 ++ src/CMakeLists.txt | 4 + src/graphics/2d.cpp | 8 + src/graphics/grgl1.cpp | 202 ++------ src/graphics/grgl1render.cpp | 4 +- src/graphics/grgl1texture.cpp | 6 +- src/graphics/grgl2.cpp | 409 ++++++++++++++++ src/graphics/grgl2render.cpp | 866 ++++++++++++++++++++++++++++++++++ src/graphics/grgl2shader.cpp | 178 +++++++ src/graphics/grgl2texture.cpp | 517 ++++++++++++++++++++ src/graphics/gropengl.cpp | 196 ++++++-- src/graphics/grwxgl.cpp | 22 +- src/movie/mveplayer.cpp | 2 + 18 files changed, 2299 insertions(+), 252 deletions(-) create mode 100644 include/grgl2.h create mode 100644 src/graphics/grgl2.cpp create mode 100644 src/graphics/grgl2render.cpp create mode 100644 src/graphics/grgl2shader.cpp create mode 100644 src/graphics/grgl2texture.cpp diff --git a/include/2d.h b/include/2d.h index be224b3..3175ba6 100644 --- a/include/2d.h +++ b/include/2d.h @@ -598,6 +598,7 @@ extern void gr_activate(int active); void gr_set_color_fast(color *dst); void gr_get_color(int *r, int *g, int *b); +void gr_get_colorf(float *r, float *g, float *b, float *a); void gr_init_color(color *c, int r, int g, int b); void gr_init_alphacolor(color *clr, int r, int g, int b, int alpha, int type); void gr_set_color(int r, int g, int b); diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 85818a4..409b07d 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -61,6 +61,7 @@ set(code_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/gamesnd.h ${CMAKE_CURRENT_SOURCE_DIR}/grinternal.h ${CMAKE_CURRENT_SOURCE_DIR}/grgl1.h + ${CMAKE_CURRENT_SOURCE_DIR}/grgl2.h ${CMAKE_CURRENT_SOURCE_DIR}/gropengl.h ${CMAKE_CURRENT_SOURCE_DIR}/gropenglinternal.h ${CMAKE_CURRENT_SOURCE_DIR}/grstub.h diff --git a/include/grgl1.h b/include/grgl1.h index 85b6dbc..a1fcd67 100644 --- a/include/grgl1.h +++ b/include/grgl1.h @@ -12,30 +12,10 @@ #include "pstypes.h" -typedef enum gr_texture_source { - TEXTURE_SOURCE_NONE, - TEXTURE_SOURCE_DECAL, - TEXTURE_SOURCE_NO_FILTERING, -} gr_texture_source; - -typedef enum gr_alpha_blend { - ALPHA_BLEND_NONE, // 1*SrcPixel + 0*DestPixel - ALPHA_BLEND_ADDITIVE, // 1*SrcPixel + 1*DestPixel - ALPHA_BLEND_ALPHA_ADDITIVE, // Alpha*SrcPixel + 1*DestPixel - ALPHA_BLEND_ALPHA_BLEND_ALPHA, // Alpha*SrcPixel + (1-Alpha)*DestPixel - ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR, // Alpha*SrcPixel + (1-SrcPixel)*DestPixel -} gr_alpha_blend; - -typedef enum gr_zbuffer_type { - ZBUFFER_TYPE_NONE, - ZBUFFER_TYPE_READ, - ZBUFFER_TYPE_WRITE, - ZBUFFER_TYPE_FULL, -} gr_zbuffer_type; extern PFNGLSECONDARYCOLORPOINTERPROC vglSecondaryColorPointer; -void opengl1_init(); +int opengl1_init(); void opengl1_cleanup(); void opengl1_set_state(gr_texture_source ts, gr_alpha_blend ab, gr_zbuffer_type zt); @@ -66,14 +46,9 @@ void gr_opengl1_save_mouse_area(int x, int y, int w, int h); void gr_opengl1_set_gamma(float gamma); void gr_opengl1_preload_init(); int gr_opengl1_preload(int bitmap_num, int is_aabitmap); -void gr_opengl1_activate(int active); -void gr_opengl1_clear(); void gr_opengl1_flip(); -void gr_opengl1_set_clip(int x,int y,int w,int h); -void gr_opengl1_reset_clip(); -void gr_opengl1_print_screen(const char *filename); +void gr_opengl1_set_clip(int x, int y, int w, int h); void gr_opengl1_fog_set(int fog_mode, int r, int g, int b, float fog_near, float fog_far); -void gr_opengl1_set_cull(int cull); void gr_opengl1_zbuffer_clear(int mode); void gr_opengl1_fade_in(int instantaneous); void gr_opengl1_fade_out(int instantaneous); @@ -85,9 +60,6 @@ void gr_opengl1_free_screen(int id); void gr_opengl1_dump_frame_start(int first_frame, int frames_between_dumps); void gr_opengl1_dump_frame_stop(); void gr_opengl1_dump_frame(); -uint gr_opengl1_lock(); -void gr_opengl1_unlock(); -void gr_opengl1_zbias(int bias); void gr_opengl1_set_viewport(int width, int height); void gr_opengl1_release_texture(int handle); diff --git a/include/grgl2.h b/include/grgl2.h new file mode 100644 index 0000000..212b7a0 --- /dev/null +++ b/include/grgl2.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) Volition, Inc. 1999. All rights reserved. + * + * All source code herein is the property of Volition, Inc. You may not sell + * or otherwise commercially exploit the source or things you created based on + * the source. + */ + +#ifndef GRGL2_H +#define GRGL2_H + +#include "pstypes.h" + + +int opengl2_init(); +void opengl2_cleanup(); +void opengl2_set_state(gr_texture_source ts, gr_alpha_blend ab, gr_zbuffer_type zt); + +void opengl2_tcache_init(); +void opengl2_tcache_cleanup(); +void opengl2_tcache_frame(); +void opengl2_tcache_flush(); +int opengl2_tcache_set(int bitmap_id, int bitmap_type, float *u_scale, float *v_scale, int fail_on_full); +void opengl2_set_texture_state(gr_texture_source ts); + +int opengl2_shader_init(); +void opengl2_shader_cleanup(); + +void opengl2_error_check(const char *name, int lno); + +// gr_* pointer functions +void gr_opengl2_flip(); +void gr_opengl2_set_clip(int x, int y, int w, int h); +void gr_opengl2_fog_set(int fog_mode, int r, int g, int b, float fog_near, float fog_far); +void gr_opengl2_zbuffer_clear(int mode); +void gr_opengl2_fade_in(int instantaneous); +void gr_opengl2_fade_out(int instantaneous); +void gr_opengl2_get_region(int front, int w, int h, ubyte *data); +int gr_opengl2_save_screen(); +void gr_opengl2_restore_screen(int); +void gr_opengl2_free_screen(int); +void gr_opengl2_dump_frame_start(int first_frame, int frames_between_dumps); +void gr_opengl2_dump_frame_stop(); +void gr_opengl2_dump_frame(); +void gr_opengl2_set_viewport(int width, int height); +void gr_opengl2_preload_init(); +int gr_opengl2_preload(int bitmap_num, int is_aabitmap); +void gr_opengl2_set_gamma(float); +void gr_opengl2_release_texture(int handle); +void gr_opengl2_rect(int x, int y, int w, int h); +void gr_opengl2_shade(int x, int y, int w, int h); +void gr_opengl2_aabitmap_ex(int x, int y, int w, int h, int sx, int sy); +void gr_opengl2_aabitmap(int x, int y); +void gr_opengl2_string(int sx, int sy, const char *s); +void gr_opengl2_line(int x1, int y1, int x2, int y2); +void gr_opengl2_aaline(vertex *v1, vertex *v2); +void gr_opengl2_gradient(int x1, int y1, int x2, int y2); +void gr_opengl2_circle(int xc, int yc, int d); +void gr_opengl2_pixel(int x, int y); +void gr_opengl2_cross_fade(int bmap1, int bmap2, int x1, int y1, int x2, int y2, float pct); +void gr_opengl2_flash(int r, int g, int b); +void gr_opengl2_tmapper(int nverts, vertex **verts, uint flags); +void gr_opengl2_scaler(vertex *va, vertex *vb); + +#endif // GRGL2_H diff --git a/include/gropengl.h b/include/gropengl.h index 34dc2e1..75aaad3 100644 --- a/include/gropengl.h +++ b/include/gropengl.h @@ -43,8 +43,6 @@ #ifndef _GROPENGL_H #define _GROPENGL_H -#include "SDL_opengl.h" - void gr_opengl_init(); void gr_opengl_cleanup(); diff --git a/include/gropenglinternal.h b/include/gropenglinternal.h index edf7673..7413255 100644 --- a/include/gropenglinternal.h +++ b/include/gropenglinternal.h @@ -12,7 +12,32 @@ #include "2d.h" +typedef enum gr_texture_source { + TEXTURE_SOURCE_NONE, + TEXTURE_SOURCE_DECAL, + TEXTURE_SOURCE_NO_FILTERING, +} gr_texture_source; + +typedef enum gr_alpha_blend { + ALPHA_BLEND_NONE, // 1*SrcPixel + 0*DestPixel + ALPHA_BLEND_ADDITIVE, // 1*SrcPixel + 1*DestPixel + ALPHA_BLEND_ALPHA_ADDITIVE, // Alpha*SrcPixel + 1*DestPixel + ALPHA_BLEND_ALPHA_BLEND_ALPHA, // Alpha*SrcPixel + (1-Alpha)*DestPixel + ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR, // Alpha*SrcPixel + (1-SrcPixel)*DestPixel +} gr_alpha_blend; + +typedef enum gr_zbuffer_type { + ZBUFFER_TYPE_NONE, + ZBUFFER_TYPE_READ, + ZBUFFER_TYPE_WRITE, + ZBUFFER_TYPE_FULL, +} gr_zbuffer_type; + +extern volatile int GL_activate; +extern volatile int GL_deactivate; + extern SDL_Window *GL_window; +extern SDL_GLContext GL_context; extern int GL_version; @@ -28,6 +53,9 @@ extern int GL_min_texture_height; extern int GL_max_texture_height; +void opengl_set_variables(); +void opengl_init_viewport(); + void opengl_alloc_render_buffer(unsigned int nelems); void opengl_free_render_buffer(); @@ -45,5 +73,13 @@ extern rb_t *render_buffer; void gr_opengl_force_fullscreen(); void gr_opengl_force_windowed(); void gr_opengl_toggle_fullscreen(); +void gr_opengl_clear(); +void gr_opengl_reset_clip(); +void gr_opengl_print_screen(const char *filename); +uint gr_opengl_lock(); +void gr_opengl_unlock(); +void gr_opengl_zbias(int bias); +void gr_opengl_set_cull(int cull); +void gr_opengl_activate(int active); #endif // _OPENGLINTERNAL_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 48f565e..779e241 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -39,6 +39,10 @@ set(code_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/graphics/grgl1.cpp ${CMAKE_CURRENT_SOURCE_DIR}/graphics/grgl1render.cpp ${CMAKE_CURRENT_SOURCE_DIR}/graphics/grgl1texture.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/graphics/grgl2.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/graphics/grgl2render.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/graphics/grgl2shader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/graphics/grgl2texture.cpp ${CMAKE_CURRENT_SOURCE_DIR}/graphics/gropengl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/graphics/grstub.cpp ${CMAKE_CURRENT_SOURCE_DIR}/graphics/grwxgl.cpp diff --git a/src/graphics/2d.cpp b/src/graphics/2d.cpp index c08a38f..208e453 100644 --- a/src/graphics/2d.cpp +++ b/src/graphics/2d.cpp @@ -1147,6 +1147,14 @@ void gr_get_color(int *r, int *g, int *b) if (b) *b = gr_screen.current_color.blue; } +void gr_get_colorf(float *r, float *g, float *b, float *a) +{ + if (r) *r = gr_screen.current_color.red / 255.0f; + if (g) *g = gr_screen.current_color.green / 255.0f; + if (b) *b = gr_screen.current_color.blue / 255.0f; + if (a) *a = gr_screen.current_color.alpha / 255.0f; +} + void gr_init_color(color *c, int r, int g, int b) { c->screen_sig = gr_screen.signature; diff --git a/src/graphics/grgl1.cpp b/src/graphics/grgl1.cpp index 2623669..589f20d 100644 --- a/src/graphics/grgl1.cpp +++ b/src/graphics/grgl1.cpp @@ -6,15 +6,19 @@ * the source. */ +#include "SDL_opengl.h" + #include "gropengl.h" -#include "grgl1.h" #include "gropenglinternal.h" +#include "grgl1.h" #include "2d.h" #include "mouse.h" #include "pstypes.h" #include "cfile.h" #include "bmpman.h" #include "grinternal.h" +#include "osapi.h" +#include "osregistry.h" int OGL_fog_mode = 0; @@ -22,9 +26,6 @@ int OGL_fog_mode = 0; int GL_one_inited = 0; -volatile int GL_activate = 0; -volatile int GL_deactivate = 0; - static GLuint Gr_saved_screen_tex = 0; static int Gr_opengl_mouse_saved = 0; @@ -101,8 +102,8 @@ void opengl1_cleanup() return; } - gr_opengl1_reset_clip(); - gr_opengl1_clear(); + gr_opengl_reset_clip(); + gr_opengl_clear(); gr_opengl1_flip(); gr_opengl1_free_screen(0); @@ -121,9 +122,9 @@ static void opengl1_init_func_pointers() { gr_screen.gf_flip = gr_opengl1_flip; gr_screen.gf_set_clip = gr_opengl1_set_clip; - gr_screen.gf_reset_clip = gr_opengl1_reset_clip; + gr_screen.gf_reset_clip = gr_opengl_reset_clip; - gr_screen.gf_clear = gr_opengl1_clear; + gr_screen.gf_clear = gr_opengl_clear; gr_screen.gf_aabitmap = gr_opengl1_aabitmap; gr_screen.gf_aabitmap_ex = gr_opengl1_aabitmap_ex; @@ -141,7 +142,7 @@ static void opengl1_init_func_pointers() gr_screen.gf_gradient = gr_opengl1_gradient; - gr_screen.gf_print_screen = gr_opengl1_print_screen; + gr_screen.gf_print_screen = gr_opengl_print_screen; gr_screen.gf_fade_in = gr_opengl1_fade_in; gr_screen.gf_fade_out = gr_opengl1_fade_out; @@ -159,21 +160,21 @@ static void opengl1_init_func_pointers() gr_screen.gf_set_gamma = gr_opengl1_set_gamma; - gr_screen.gf_lock = gr_opengl1_lock; - gr_screen.gf_unlock = gr_opengl1_unlock; + gr_screen.gf_lock = gr_opengl_lock; + gr_screen.gf_unlock = gr_opengl_unlock; gr_screen.gf_fog_set = gr_opengl1_fog_set; gr_screen.gf_get_region = gr_opengl1_get_region; - gr_screen.gf_set_cull = gr_opengl1_set_cull; + gr_screen.gf_set_cull = gr_opengl_set_cull; gr_screen.gf_cross_fade = gr_opengl1_cross_fade; gr_screen.gf_preload_init = gr_opengl1_preload_init; gr_screen.gf_preload = gr_opengl1_preload; - gr_screen.gf_zbias = gr_opengl1_zbias; + gr_screen.gf_zbias = gr_opengl_zbias; gr_screen.gf_force_windowed = gr_opengl_force_windowed; gr_screen.gf_force_fullscreen = gr_opengl_force_fullscreen; @@ -181,17 +182,36 @@ static void opengl1_init_func_pointers() gr_screen.gf_set_viewport = gr_opengl1_set_viewport; - gr_screen.gf_activate = gr_opengl1_activate; + gr_screen.gf_activate = gr_opengl_activate; gr_screen.gf_release_texture = gr_opengl1_release_texture; } -void opengl1_init() +int opengl1_init() { if (GL_one_inited) { - return; + return 1; } + GL_context = SDL_GL_CreateContext(GL_window); + + if ( !GL_context ) { + return 0; + } + + mprintf((" Vendor : %s\n", glGetString(GL_VENDOR))); + mprintf((" Renderer : %s\n", glGetString(GL_RENDERER))); + mprintf((" Version : %s\n", glGetString(GL_VERSION))); + + // set up generic variables + opengl_set_variables(); + + opengl1_init_func_pointers(); + opengl1_tcache_init(); + + // initial viewport setup + gr_opengl1_set_viewport(gr_screen.max_w, gr_screen.max_h); + /* 1 = use secondary color ext 2 = use opengl linear fog @@ -224,39 +244,12 @@ void opengl1_init() glFlush(); - opengl1_init_func_pointers(); - opengl1_tcache_init(); - - gr_opengl1_clear(); - gr_opengl1_set_cull(1); + gr_opengl_clear(); + gr_opengl_set_cull(1); GL_one_inited = 1; -} -void gr_opengl1_activate(int active) -{ - if (active) { - GL_activate++; - - // don't grab key/mouse if cmdline says so or if we're fullscreen - // if(!Cmdline_no_grab && !(SDL_GetVideoSurface()->flags & SDL_FULLSCREEN)) { - // SDL_WM_GrabInput(SDL_GRAB_ON); - // } - } else { - GL_deactivate++; - - // let go of mouse/keyboard - // SDL_WM_GrabInput(SDL_GRAB_OFF); - } -} - -void gr_opengl1_clear() -{ - glClearColor(gr_screen.current_clear_color.red / 255.0f, - gr_screen.current_clear_color.green / 255.0f, - gr_screen.current_clear_color.blue / 255.0f, 1.0f); - - glClear( GL_COLOR_BUFFER_BIT ); + return 1; } void gr_opengl1_flip() @@ -274,7 +267,6 @@ void gr_opengl1_flip() if ( mouse_is_visible() ) { int mx, my; - gr_reset_clip(); mouse_get_pos( &mx, &my ); gr_opengl1_save_mouse_area(mx,my,32,32); @@ -322,28 +314,13 @@ void gr_opengl1_flip() } } -void gr_opengl1_set_clip(int x,int y,int w,int h) +void gr_opengl1_set_clip(int x, int y, int w, int h) { // check for sanity of parameters - if (x < 0) - x = 0; - if (y < 0) - y = 0; - - if (x >= gr_screen.max_w) - x = gr_screen.max_w - 1; - if (y >= gr_screen.max_h) - y = gr_screen.max_h - 1; - - if (x + w > gr_screen.max_w) - w = gr_screen.max_w - x; - if (y + h > gr_screen.max_h) - h = gr_screen.max_h - y; - - if (w > gr_screen.max_w) - w = gr_screen.max_w; - if (h > gr_screen.max_h) - h = gr_screen.max_h; + CAP(x, 0, gr_screen.max_w - 1); + CAP(y, 0, gr_screen.max_h - 1); + CAP(w, 0, gr_screen.max_w - x); + CAP(h, 0, gr_screen.max_h - y); gr_screen.offset_x = x; gr_screen.offset_y = y; @@ -363,66 +340,6 @@ void gr_opengl1_set_clip(int x,int y,int w,int h) glScissor(x, GL_viewport_h-y-h, w, h); } -void gr_opengl1_reset_clip() -{ - gr_screen.offset_x = 0; - gr_screen.offset_y = 0; - gr_screen.clip_left = 0; - gr_screen.clip_top = 0; - gr_screen.clip_right = gr_screen.max_w - 1; - gr_screen.clip_bottom = gr_screen.max_h - 1; - gr_screen.clip_width = gr_screen.max_w; - gr_screen.clip_height = gr_screen.max_h; - - glDisable(GL_SCISSOR_TEST); -} - -void gr_opengl1_print_screen(const char *filename) -{ - char tmp[MAX_FILENAME_LEN]; - ubyte *buf = NULL; - - SDL_strlcpy( tmp, filename, SDL_arraysize(tmp) ); - SDL_strlcat( tmp, NOX(".tga"), SDL_arraysize(tmp) ); - - buf = (ubyte*)malloc(GL_viewport_w * GL_viewport_h * 3); - - if (buf == NULL) { - return; - } - - CFILE *f = cfopen(tmp, "wb", CFILE_NORMAL, CF_TYPE_ROOT); - - if (f == NULL) { - free(buf); - return; - } - - // Write the TGA header - cfwrite_ubyte( 0, f ); // IDLength; - cfwrite_ubyte( 0, f ); // ColorMapType; - cfwrite_ubyte( 2, f ); // ImageType; // 2 = 24bpp, uncompressed, 10=24bpp rle compressed - cfwrite_ushort( 0, f ); // CMapStart; - cfwrite_ushort( 0, f ); // CMapLength; - cfwrite_ubyte( 0, f ); // CMapDepth; - cfwrite_ushort( 0, f ); // XOffset; - cfwrite_ushort( 0, f ); // YOffset; - cfwrite_ushort( (ushort)GL_viewport_w, f ); // Width; - cfwrite_ushort( (ushort)GL_viewport_h, f ); // Height; - cfwrite_ubyte( 24, f ); //PixelDepth; - cfwrite_ubyte( 0, f ); //ImageDesc; - - memset(buf, 0, GL_viewport_w * GL_viewport_h * 3); - - glReadPixels(GL_viewport_x, GL_viewport_y, GL_viewport_w, GL_viewport_h, GL_RGB, GL_UNSIGNED_BYTE, buf); - - cfwrite(buf, GL_viewport_w * GL_viewport_h * 3, 1, f); - - cfclose(f); - - free(buf); -} - void gr_opengl1_fog_set(int fog_mode, int r, int g, int b, float fog_near, float fog_far) { SDL_assert((r >= 0) && (r < 256)); @@ -483,16 +400,6 @@ void gr_opengl1_fog_set(int fog_mode, int r, int g, int b, float fog_near, float } } -void gr_opengl1_set_cull(int cull) -{ - if (cull) { - glEnable (GL_CULL_FACE); - glFrontFace (GL_CCW); - } else { - glDisable (GL_CULL_FACE); - } -} - void gr_opengl1_zbuffer_clear(int mode) { if (mode) { @@ -698,25 +605,6 @@ void gr_opengl1_dump_frame() STUB_FUNCTION; } -uint gr_opengl1_lock() -{ - return 1; -} - -void gr_opengl1_unlock() -{ -} - -void gr_opengl1_zbias(int bias) -{ - if (bias) { - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(0.0f, GLfloat(-bias)); - } else { - glDisable(GL_POLYGON_OFFSET_FILL); - } -} - void gr_opengl1_set_viewport(int width, int height) { int w, h, x, y; @@ -757,5 +645,5 @@ void gr_opengl1_set_viewport(int width, int height) } // clear screen once to fix issues with edges on non-4:3 - gr_opengl1_clear(); + gr_opengl_clear(); } diff --git a/src/graphics/grgl1render.cpp b/src/graphics/grgl1render.cpp index 350a659..a8d8032 100644 --- a/src/graphics/grgl1render.cpp +++ b/src/graphics/grgl1render.cpp @@ -6,11 +6,13 @@ * the source. */ +#include "SDL_opengl.h" + #include "pstypes.h" #include "2d.h" #include "gropengl.h" -#include "grgl1.h" #include "gropenglinternal.h" +#include "grgl1.h" #include "bmpman.h" #include "grinternal.h" #include "3d.h" diff --git a/src/graphics/grgl1texture.cpp b/src/graphics/grgl1texture.cpp index 3df3d68..db4f91d 100644 --- a/src/graphics/grgl1texture.cpp +++ b/src/graphics/grgl1texture.cpp @@ -6,18 +6,20 @@ * the source. */ +#include "SDL_opengl.h" + #include "pstypes.h" #include "2d.h" #include "gropengl.h" -#include "grgl1.h" #include "gropenglinternal.h" +#include "grgl1.h" #include "bmpman.h" #include "grinternal.h" #include "systemvars.h" #include "osregistry.h" -int vram_full = 0; +static int vram_full = 0; typedef struct tcache_slot_opengl { GLuint texture_handle; diff --git a/src/graphics/grgl2.cpp b/src/graphics/grgl2.cpp new file mode 100644 index 0000000..2ee7afc --- /dev/null +++ b/src/graphics/grgl2.cpp @@ -0,0 +1,409 @@ +/* + * Copyright (C) Volition, Inc. 1999. All rights reserved. + * + * All source code herein is the property of Volition, Inc. You may not sell + * or otherwise commercially exploit the source or things you created based on + * the source. + */ + +#include "SDL_opengles2.h" + +#include "gropengl.h" +#include "gropenglinternal.h" +#include "grgl2.h" +#include "2d.h" +#include "mouse.h" +#include "pstypes.h" +#include "cfile.h" +#include "bmpman.h" +#include "grinternal.h" +#include "osapi.h" +#include "osregistry.h" + + +int GL_two_inited = 0; + +bool Use_mipmaps = false; + + +static gr_alpha_blend GL_current_alpha_blend = (gr_alpha_blend) -1; +static gr_zbuffer_type GL_current_zbuffer_type = (gr_zbuffer_type) -1; + +void opengl2_set_state(gr_texture_source ts, gr_alpha_blend ab, gr_zbuffer_type zt) +{ + opengl2_set_texture_state(ts); + + if (ab != GL_current_alpha_blend) { + switch (ab) { + case ALPHA_BLEND_NONE: // 1*SrcPixel + 0*DestPixel + glBlendFunc(GL_ONE, GL_ZERO); + break; + case ALPHA_BLEND_ADDITIVE: // 1*SrcPixel + 1*DestPixel + glBlendFunc(GL_ONE, GL_ONE); + break; + case ALPHA_BLEND_ALPHA_ADDITIVE: // Alpha*SrcPixel + 1*DestPixel + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + break; + case ALPHA_BLEND_ALPHA_BLEND_ALPHA: // Alpha*SrcPixel + (1-Alpha)*DestPixel + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + case ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR: // Alpha*SrcPixel + (1-SrcPixel)*DestPixel + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR); + break; + default: + break; + } + + GL_current_alpha_blend = ab; + } + + if (zt != GL_current_zbuffer_type) { + switch (zt) { + case ZBUFFER_TYPE_NONE: + glDepthFunc(GL_ALWAYS); + glDepthMask(GL_FALSE); + break; + case ZBUFFER_TYPE_READ: + glDepthFunc(GL_LESS); + glDepthMask(GL_FALSE); + break; + case ZBUFFER_TYPE_WRITE: + glDepthFunc(GL_ALWAYS); + glDepthMask(GL_TRUE); + break; + case ZBUFFER_TYPE_FULL: + glDepthFunc(GL_LESS); + glDepthMask(GL_TRUE); + break; + default: + break; + } + + GL_current_zbuffer_type = zt; + } +} + +void opengl2_cleanup() +{ + if ( !GL_two_inited ) { + return; + } + + opengl2_tcache_cleanup(); + opengl2_shader_cleanup(); + + GL_two_inited = 0; +} + +static void opengl2_init_func_pointers() +{ + gr_screen.gf_flip = gr_opengl2_flip; + gr_screen.gf_set_clip = gr_opengl2_set_clip; + gr_screen.gf_reset_clip = gr_opengl_reset_clip; + + gr_screen.gf_clear = gr_opengl_clear; + + gr_screen.gf_aabitmap = gr_opengl2_aabitmap; + gr_screen.gf_aabitmap_ex = gr_opengl2_aabitmap_ex; + + gr_screen.gf_rect = gr_opengl2_rect; + gr_screen.gf_shade = gr_opengl2_shade; + gr_screen.gf_string = gr_opengl2_string; + gr_screen.gf_circle = gr_opengl2_circle; + + gr_screen.gf_line = gr_opengl2_line; + gr_screen.gf_aaline = gr_opengl2_aaline; + gr_screen.gf_pixel = gr_opengl2_pixel; + gr_screen.gf_scaler = gr_opengl2_scaler; + gr_screen.gf_tmapper = gr_opengl2_tmapper; + + gr_screen.gf_gradient = gr_opengl2_gradient; + + gr_screen.gf_print_screen = gr_opengl_print_screen; + + gr_screen.gf_fade_in = gr_opengl2_fade_in; + gr_screen.gf_fade_out = gr_opengl2_fade_out; + gr_screen.gf_flash = gr_opengl2_flash; + + gr_screen.gf_zbuffer_clear = gr_opengl2_zbuffer_clear; + + gr_screen.gf_save_screen = gr_opengl2_save_screen; + gr_screen.gf_restore_screen = gr_opengl2_restore_screen; + gr_screen.gf_free_screen = gr_opengl2_free_screen; + + gr_screen.gf_dump_frame_start = gr_opengl2_dump_frame_start; + gr_screen.gf_dump_frame_stop = gr_opengl2_dump_frame_stop; + gr_screen.gf_dump_frame = gr_opengl2_dump_frame; + + gr_screen.gf_set_gamma = gr_opengl2_set_gamma; + + gr_screen.gf_lock = gr_opengl_lock; + gr_screen.gf_unlock = gr_opengl_unlock; + + gr_screen.gf_fog_set = gr_opengl2_fog_set; + + gr_screen.gf_get_region = gr_opengl2_get_region; + + gr_screen.gf_set_cull = gr_opengl_set_cull; + + gr_screen.gf_cross_fade = gr_opengl2_cross_fade; + + gr_screen.gf_preload_init = gr_opengl2_preload_init; + gr_screen.gf_preload = gr_opengl2_preload; + + gr_screen.gf_zbias = gr_opengl_zbias; + + gr_screen.gf_force_windowed = gr_opengl_force_windowed; + gr_screen.gf_force_fullscreen = gr_opengl_force_fullscreen; + gr_screen.gf_toggle_fullscreen = gr_opengl_toggle_fullscreen; + + gr_screen.gf_set_viewport = gr_opengl2_set_viewport; + + gr_screen.gf_activate = gr_opengl_activate; + + gr_screen.gf_release_texture = gr_opengl2_release_texture; +} + +int opengl2_init() +{ + if (GL_two_inited) { + return 1; + } + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + + GL_context = SDL_GL_CreateContext(GL_window); + + if ( !GL_context ) { + return 0; + } + + mprintf((" Vendor : %s\n", glGetString(GL_VENDOR))); + mprintf((" Renderer : %s\n", glGetString(GL_RENDERER))); + mprintf((" Version : %s\n", glGetString(GL_VERSION))); + + // set up generic variables + opengl_set_variables(); + + opengl2_init_func_pointers(); + opengl2_tcache_init(); + opengl2_shader_init(); + + // initial viewport setup + gr_opengl2_set_viewport(gr_screen.max_w, gr_screen.max_h); + + glEnable(GL_DITHER); + glEnable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + + glDepthRangef(0.0f, 1.0f); + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + if ( SDL_GL_ExtensionSupported("GL_OES_texture_npot") ) { + Use_mipmaps = true; + } + + mprintf((" Mipmaps : %s\n", Use_mipmaps ? "Enabled" : "Disabled")); + + glFlush(); + + gr_opengl_clear(); + gr_opengl_set_cull(1); + + GL_two_inited = 1; + + return 1; +} + +void gr_opengl2_flip() +{ + if ( !GL_two_inited ) { + return; + } + + gr_opengl_reset_clip(); + + mouse_eval_deltas(); + + if ( mouse_is_visible() ) { + int mx, my; + + mouse_get_pos(&mx, &my); + + if (Gr_cursor == -1) { +#ifndef NDEBUG + gr_set_color(255, 255, 255); + gr_opengl2_line(mx, my, mx+7, my+7); + gr_opengl2_line(mx, my, mx+5, my); + gr_opengl2_line(mx, my, mx, my+5); +#endif + } else { + gr_set_bitmap(Gr_cursor); + gr_bitmap(mx, my); + } + } + +#ifndef NDEBUG + GLenum error = GL_NO_ERROR; + + do { + error = glGetError(); + + if (error != GL_NO_ERROR) { + nprintf(("Warning", "!!DEBUG!! OpenGL Error: %d\n", error)); + } + } while (error != GL_NO_ERROR); +#endif + + SDL_GL_SwapWindow(GL_window); + + opengl2_tcache_frame(); +} + +void gr_opengl2_set_clip(int x, int y, int w, int h) +{ + // check for sanity of parameters + CAP(x, 0, gr_screen.max_w - 1); + CAP(y, 0, gr_screen.max_h - 1); + CAP(w, 0, gr_screen.max_w - x); + CAP(h, 0, gr_screen.max_h - y); + + gr_screen.offset_x = x; + gr_screen.offset_y = y; + gr_screen.clip_left = 0; + gr_screen.clip_right = w-1; + gr_screen.clip_top = 0; + gr_screen.clip_bottom = h-1; + gr_screen.clip_width = w; + gr_screen.clip_height = h; + + glEnable(GL_SCISSOR_TEST); + glScissor(x, GL_viewport_h-y-h, w, h); +} + +void gr_opengl2_fog_set(int fog_mode, int r, int g, int b, float fog_near, float fog_far) +{ + gr_screen.current_fog_mode = fog_mode; + gr_screen.fog_near = fog_near; + gr_screen.fog_far = fog_far; + + gr_init_color(&gr_screen.current_fog_color, r, g, b); +} + +void gr_opengl2_zbuffer_clear(int mode) +{ + if (mode) { + Gr_zbuffering = 1; + Gr_zbuffering_mode = GR_ZBUFF_FULL; + Gr_global_zbuffering = 1; + + opengl2_set_state(TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_FULL); + glClear(GL_DEPTH_BUFFER_BIT); + } else { + Gr_zbuffering = 0; + Gr_zbuffering_mode = GR_ZBUFF_NONE; + Gr_global_zbuffering = 0; + } +} + +void gr_opengl2_fade_in(int instantaneous) +{ + +} + +void gr_opengl2_fade_out(int instantaneous) +{ + +} + +void gr_opengl2_get_region(int front, int w, int h, ubyte *data) +{ + +} + +int gr_opengl2_save_screen() +{ + return -1; +} + +void gr_opengl2_restore_screen(int) +{ + +} + +void gr_opengl2_free_screen(int) +{ + +} + +void gr_opengl2_dump_frame_start(int first_frame, int frames_between_dumps) +{ + +} + +void gr_opengl2_dump_frame_stop() +{ + +} + +void gr_opengl2_dump_frame() +{ + +} + +void gr_opengl2_set_viewport(int width, int height) +{ + int w, h, x, y; + + float ratio = gr_screen.max_w / i2fl(gr_screen.max_h); + + w = width; + h = fl2i((width / ratio) + 0.5f); + + if (h > height) { + h = height; + w = fl2i((height * ratio) + 0.5f); + } + + x = (width - w) / 2; + y = (height - h) / 2; + + GL_viewport_x = x; + GL_viewport_y = y; + GL_viewport_w = w; + GL_viewport_h = h; + GL_viewport_scale_w = w / i2fl(gr_screen.max_w); + GL_viewport_scale_h = h / i2fl(gr_screen.max_h); + + glViewport(GL_viewport_x, GL_viewport_y, GL_viewport_w, GL_viewport_h); + + int left = 0, right = GL_viewport_w; + int top = 0, bottom = GL_viewport_h; + int far = 1.0f, near = 0.0f; + + float a = 2.0f / (right - left); + float b = 2.0f / (top - bottom); + float c = -2.0f / (far - near); + + float tx = - (right + left)/(right - left); + float ty = - (top + bottom)/(top - bottom); + float tz = - (far + near)/(far - near); + + float ortho[16] = { + a, 0, 0, 0, + 0, b, 0, 0, + 0, 0, c, 0, + tx, ty, tz, 1 + }; + + extern GLuint basicTexture; + GLint loc = glGetUniformLocation(basicTexture, "vOrtho"); + glUniformMatrix4fv(loc, 1, GL_FALSE, ortho); + + // clear screen once to fix issues with edges on non-4:3 + gr_opengl_clear(); +} diff --git a/src/graphics/grgl2render.cpp b/src/graphics/grgl2render.cpp new file mode 100644 index 0000000..1ff818f --- /dev/null +++ b/src/graphics/grgl2render.cpp @@ -0,0 +1,866 @@ +/* + * Copyright (C) Volition, Inc. 1999. All rights reserved. + * + * All source code herein is the property of Volition, Inc. You may not sell + * or otherwise commercially exploit the source or things you created based on + * the source. + */ + +#include "SDL_opengles2.h" + +#include "pstypes.h" +#include "2d.h" +#include "gropengl.h" +#include "gropenglinternal.h" +#include "grgl2.h" +#include "bmpman.h" +#include "grinternal.h" +#include "3d.h" +#include "neb.h" +#include "line.h" +#include "palman.h" + + +#define NEBULA_COLORS 20 + +int cntZval = 0; +int cntCorrect = 0; +int cntAlpha = 0; +int cntNebula = 0; +int cntRamp = 0; +int cntRGB = 0; + +static void opengl2_tmapper_internal(int nv, vertex **verts, uint flags, int is_scaler) +{ + int i; + float u_scale = 1.0f, v_scale = 1.0f; + + gr_texture_source texture_source = TEXTURE_SOURCE_NONE; + gr_alpha_blend alpha_blend = ALPHA_BLEND_ALPHA_BLEND_ALPHA; + gr_zbuffer_type zbuffer_type = ZBUFFER_TYPE_NONE; + + if (Gr_zbuffering) { + if ( is_scaler || (gr_screen.current_alphablend_mode == GR_ALPHABLEND_FILTER) ) { + zbuffer_type = ZBUFFER_TYPE_READ; + } else { + zbuffer_type = ZBUFFER_TYPE_FULL; + } + } + + int tmap_type = TCACHE_TYPE_NORMAL; + + ubyte r = 255, g = 255, b = 255, a = 255; + + if ( !(flags & TMAP_FLAG_TEXTURED) ) { + r = gr_screen.current_color.red; + g = gr_screen.current_color.green; + b = gr_screen.current_color.blue; + } + + if (gr_screen.current_alphablend_mode == GR_ALPHABLEND_FILTER) { + alpha_blend = ALPHA_BLEND_ALPHA_ADDITIVE; + + // Blend with screen pixel using src*alpha+dst + + if (gr_screen.current_alpha < 1.0f) { + r = ubyte((r * gr_screen.current_alpha) + 0.5f); + g = ubyte((g * gr_screen.current_alpha) + 0.5f); + b = ubyte((b * gr_screen.current_alpha) + 0.5f); + } + } + + if (flags & TMAP_FLAG_BITMAP_SECTION) { + SDL_assert( !(flags & TMAP_FLAG_BITMAP_INTERFACE) ); + tmap_type = TCACHE_TYPE_BITMAP_SECTION; + } else if (flags & TMAP_FLAG_BITMAP_INTERFACE) { + SDL_assert( !(flags & TMAP_FLAG_BITMAP_SECTION) ); + tmap_type = TCACHE_TYPE_BITMAP_INTERFACE; + } + + if (flags & TMAP_FLAG_TEXTURED) { + if ( !opengl2_tcache_set(gr_screen.current_bitmap, tmap_type, &u_scale, + &v_scale, 0) ) + { + mprintf(( "Not rendering a texture because it didn't fit in VRAM!\n" )); + return; + } + + // use non-filtered textures for bitmap sections and UI graphics + switch (tmap_type) { + case TCACHE_TYPE_BITMAP_INTERFACE: + case TCACHE_TYPE_BITMAP_SECTION: + texture_source = TEXTURE_SOURCE_NO_FILTERING; + break; + + default: + texture_source = TEXTURE_SOURCE_DECAL; + break; + } + } + + + opengl2_set_state( texture_source, alpha_blend, zbuffer_type ); + + float ox = gr_screen.offset_x * 16.0f; + float oy = gr_screen.offset_y * 16.0f; +/* + float fr = 1.0f, fg = 1.0f, fb = 1.0f; + + if (flags & TMAP_FLAG_PIXEL_FOG) { + int r, g, b; + int ra, ga, ba; + float sx, sy; + + ra = ga = ba = 0; + + for (i=nv-1;i>=0;i--) // DDOI - change polygon winding + { + vertex * va = verts[i]; + + sx = (va->sx * 16.0f + ox) / 16.0f; + sy = (va->sy * 16.0f + oy) / 16.0f; + + neb2_get_pixel((int)sx, (int)sy, &r, &g, &b); + + ra += r; + ga += g; + ba += b; + } + + ra /= nv; + ga /= nv; + ba /= nv; + + gr_fog_set(GR_FOGMODE_FOG, ra, ga, ba, -1.0f, -1.0f); + + fr = ra / 255.0f; + fg = ga / 255.0f; + fb = ba / 255.0f; + } +*/ + opengl_alloc_render_buffer(nv); + + int rb_offset = 0; + + float sx, sy, sz = 0.99f, rhw = 1.0f; + + bool bZval = (Gr_zbuffering || (flags & TMAP_FLAG_NEBULA)); + bool bCorrect = (flags & TMAP_FLAG_CORRECT); + bool bAlpha = (flags & TMAP_FLAG_ALPHA); + bool bNebula = (flags & TMAP_FLAG_NEBULA); + bool bRamp = ((flags & TMAP_FLAG_RAMP) && (flags & TMAP_FLAG_GOURAUD)); + bool bRGB = ((flags & TMAP_FLAG_RGB) && (flags & TMAP_FLAG_GOURAUD)); + bool bTextured = (flags & TMAP_FLAG_TEXTURED); + + for (i = nv-1; i >= 0; i--) { + vertex *va = verts[i]; + + if (bZval) { + sz = 1.0f - 1.0f / (1.0f + va->z / (32768.0f / 256.0f)); + + if ( sz > 0.98f ) { + sz = 0.98f; + } + } + + if (bCorrect) { + rhw = 1.0f / va->sw; + } + + if (bAlpha) { + a = va->a; + } + + if (bRGB) { + // Make 0.75 be 256.0f + r = Gr_gamma_lookup[va->r]; + g = Gr_gamma_lookup[va->g]; + b = Gr_gamma_lookup[va->b]; + } else if (bNebula) { + int pal = (va->b*(NEBULA_COLORS-1))/255; + r = gr_palette[pal*3+0]; + g = gr_palette[pal*3+1]; + b = gr_palette[pal*3+2]; + } else if (bRamp) { + r = g = b = Gr_gamma_lookup[va->b]; + } + + render_buffer[rb_offset].r = r; + render_buffer[rb_offset].g = g; + render_buffer[rb_offset].b = b; + render_buffer[rb_offset].a = a; +/* + if ( (flags & TMAP_FLAG_PIXEL_FOG) && (OGL_fog_mode == 1) ) { + float f_val; + + opengl1_stuff_fog_value(va->z, &f_val); + + render_buffer[rb_offset].sr = (ubyte)(((fr * f_val) * 255.0f) + 0.5f); + render_buffer[rb_offset].sg = (ubyte)(((fg * f_val) * 255.0f) + 0.5f); + render_buffer[rb_offset].sb = (ubyte)(((fb * f_val) * 255.0f) + 0.5f); + } +*/ + sx = (va->sx * 16.0f + ox) / 16.0f; + sy = (va->sy * 16.0f + oy) / 16.0f; + + if (bTextured) { + render_buffer[rb_offset].u = va->u * u_scale; + render_buffer[rb_offset].v = va->v * v_scale; + } + + render_buffer[rb_offset].x = sx * rhw; + render_buffer[rb_offset].y = sy * rhw; + render_buffer[rb_offset].z = -sz * rhw; + render_buffer[rb_offset].w = rhw; + + ++rb_offset; + } + + if (flags & TMAP_FLAG_TEXTURED) { + glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(rb_t), &render_buffer[0].u); + glEnableVertexAttribArray(3); + } +/* + if ( (gr_screen.current_fog_mode != GR_FOGMODE_NONE) && (OGL_fog_mode == 1) ) { + glEnableClientState(GL_SECONDARY_COLOR_ARRAY); + vglSecondaryColorPointer(3, GL_UNSIGNED_BYTE, sizeof(rb_t), &render_buffer[0].sr); + } +*/ + glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(rb_t), &render_buffer[0].r); + glEnableVertexAttribArray(2); + + glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(rb_t), &render_buffer[0].x); + glEnableVertexAttribArray(1); + + glDrawArrays(GL_TRIANGLE_FAN, 0, rb_offset); + + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); + glDisableVertexAttribArray(3); +} + +void opengl2_rect_internal(int x, int y, int w, int h, int r, int g, int b, int a) +{ + int saved_zbuf; + vertex v[4]; + vertex *verts[4] = {&v[0], &v[1], &v[2], &v[3]}; + + saved_zbuf = gr_zbuffer_get(); + + // start the frame, no zbuffering, no culling + g3_start_frame(1); + gr_zbuffer_set(GR_ZBUFF_NONE); + gr_opengl_set_cull(0); + + // stuff coords + v[0].sx = i2fl(x); + v[0].sy = i2fl(y); + v[0].sw = 0.0f; + v[0].u = 0.0f; + v[0].v = 0.0f; + v[0].flags = PF_PROJECTED; + v[0].codes = 0; + v[0].r = (ubyte)r; + v[0].g = (ubyte)g; + v[0].b = (ubyte)b; + v[0].a = (ubyte)a; + + v[1].sx = i2fl(x + w); + v[1].sy = i2fl(y); + v[1].sw = 0.0f; + v[1].u = 0.0f; + v[1].v = 0.0f; + v[1].flags = PF_PROJECTED; + v[1].codes = 0; + v[1].r = (ubyte)r; + v[1].g = (ubyte)g; + v[1].b = (ubyte)b; + v[1].a = (ubyte)a; + + v[2].sx = i2fl(x + w); + v[2].sy = i2fl(y + h); + v[2].sw = 0.0f; + v[2].u = 0.0f; + v[2].v = 0.0f; + v[2].flags = PF_PROJECTED; + v[2].codes = 0; + v[2].r = (ubyte)r; + v[2].g = (ubyte)g; + v[2].b = (ubyte)b; + v[2].a = (ubyte)a; + + v[3].sx = i2fl(x); + v[3].sy = i2fl(y + h); + v[3].sw = 0.0f; + v[3].u = 0.0f; + v[3].v = 0.0f; + v[3].flags = PF_PROJECTED; + v[3].codes = 0; + v[3].r = (ubyte)r; + v[3].g = (ubyte)g; + v[3].b = (ubyte)b; + v[3].a = (ubyte)a; + + // draw the polys + g3_draw_poly_constant_sw(4, verts, TMAP_FLAG_GOURAUD | TMAP_FLAG_RGB | TMAP_FLAG_ALPHA, 0.1f); + + g3_end_frame(); + + // restore zbuffer and culling + gr_zbuffer_set(saved_zbuf); + gr_opengl_set_cull(1); +} + +void opengl2_aabitmap_ex_internal(int x, int y, int w, int h, int sx, int sy) +{ + if ( (w < 1) || (h < 1) ) { + return; + } + + if ( !gr_screen.current_color.is_alphacolor ) { + return; + } + + float u_scale, v_scale; + + if ( !opengl2_tcache_set(gr_screen.current_bitmap, TCACHE_TYPE_AABITMAP, + &u_scale, &v_scale, 0) ) + { + // Couldn't set texture + mprintf(( "WARNING: Error setting aabitmap texture!\n" )); + return; + } + + opengl2_set_state( TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE ); + + float u0, u1, v0, v1; + float x1, x2, y1, y2; + int bw, bh; + + bm_get_info( gr_screen.current_bitmap, &bw, &bh ); + + u0 = u_scale*i2fl(sx)/i2fl(bw); + v0 = v_scale*i2fl(sy)/i2fl(bh); + + u1 = u_scale*i2fl(sx+w)/i2fl(bw); + v1 = v_scale*i2fl(sy+h)/i2fl(bh); + + x1 = i2fl(x+gr_screen.offset_x); + y1 = i2fl(y+gr_screen.offset_y); + x2 = i2fl(x+w+gr_screen.offset_x); + y2 = i2fl(y+h+gr_screen.offset_y); + + float r, g, b, a; + gr_get_colorf(&r, &g, &b, &a); + glVertexAttrib4f(1, r, g, b, a); + + opengl_alloc_render_buffer(4); + + render_buffer[0].x = x1; + render_buffer[0].y = y1; + render_buffer[0].u = u0; + render_buffer[0].v = v0; + + render_buffer[1].x = x1; + render_buffer[1].y = y2; + render_buffer[1].u = u0; + render_buffer[1].v = v1; + + render_buffer[2].x = x2; + render_buffer[2].y = y1; + render_buffer[2].u = u1; + render_buffer[2].v = v0; + + render_buffer[3].x = x2; + render_buffer[3].y = y2; + render_buffer[3].u = u1; + render_buffer[3].v = v1; + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(rb_t), &render_buffer[0].x); + glEnableVertexAttribArray(0); + + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(rb_t), &render_buffer[0].u); + glEnableVertexAttribArray(2); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(2); +} + +void gr_opengl2_rect(int x, int y, int w, int h) +{ + opengl2_rect_internal(x, y, w, h, gr_screen.current_color.red, + gr_screen.current_color.green, gr_screen.current_color.blue, + gr_screen.current_color.alpha); +} + +void gr_opengl2_shade(int x, int y, int w, int h) +{ + int r,g,b,a; + + float shade1 = 1.0f; + float shade2 = 6.0f; + + r = fl2i(gr_screen.current_shader.r*255.0f*shade1); + CAP(r, 0, 255); + g = fl2i(gr_screen.current_shader.g*255.0f*shade1); + CAP(g, 0, 255); + b = fl2i(gr_screen.current_shader.b*255.0f*shade1); + CAP(b, 0, 255); + a = fl2i(gr_screen.current_shader.c*255.0f*shade2); + CAP(a, 0, 255); + + opengl2_rect_internal(x, y, w, h, r, g, b, a); +} + +void gr_opengl2_aabitmap_ex(int x, int y, int w, int h, int sx, int sy) +{ + int reclip; + #ifndef NDEBUG + int count = 0; + #endif + + int dx1=x, dx2=x+w-1; + int dy1=y, dy2=y+h-1; + + int bw, bh; + bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL ); + + do { + reclip = 0; + #ifndef NDEBUG + if ( count > 1 ) Int3(); + count++; + #endif + + if ((dx1 > gr_screen.clip_right ) || (dx2 < gr_screen.clip_left)) return; + if ((dy1 > gr_screen.clip_bottom ) || (dy2 < gr_screen.clip_top)) return; + if ( dx1 < gr_screen.clip_left ) { sx += gr_screen.clip_left-dx1; dx1 = gr_screen.clip_left; } + if ( dy1 < gr_screen.clip_top ) { sy += gr_screen.clip_top-dy1; dy1 = gr_screen.clip_top; } + if ( dx2 > gr_screen.clip_right ) { dx2 = gr_screen.clip_right; } + if ( dy2 > gr_screen.clip_bottom ) { dy2 = gr_screen.clip_bottom; } + + if ( sx < 0 ) { + dx1 -= sx; + sx = 0; + reclip = 1; + } + + if ( sy < 0 ) { + dy1 -= sy; + sy = 0; + reclip = 1; + } + + w = dx2-dx1+1; + h = dy2-dy1+1; + + if ( sx + w > bw ) { + w = bw - sx; + dx2 = dx1 + w - 1; + } + + if ( sy + h > bh ) { + h = bh - sy; + dy2 = dy1 + h - 1; + } + + if ( w < 1 ) return; // clipped away! + if ( h < 1 ) return; // clipped away! + + } while (reclip); + + // Make sure clipping algorithm works + #ifndef NDEBUG + SDL_assert( w > 0 ); + SDL_assert( h > 0 ); + SDL_assert( w == (dx2-dx1+1) ); + SDL_assert( h == (dy2-dy1+1) ); + SDL_assert( sx >= 0 ); + SDL_assert( sy >= 0 ); + SDL_assert( sx+w <= bw ); + SDL_assert( sy+h <= bh ); + SDL_assert( dx2 >= dx1 ); + SDL_assert( dy2 >= dy1 ); + SDL_assert( (dx1 >= gr_screen.clip_left ) && (dx1 <= gr_screen.clip_right) ); + SDL_assert( (dx2 >= gr_screen.clip_left ) && (dx2 <= gr_screen.clip_right) ); + SDL_assert( (dy1 >= gr_screen.clip_top ) && (dy1 <= gr_screen.clip_bottom) ); + SDL_assert( (dy2 >= gr_screen.clip_top ) && (dy2 <= gr_screen.clip_bottom) ); + #endif + + // We now have dx1,dy1 and dx2,dy2 and sx, sy all set validly within clip regions. + opengl2_aabitmap_ex_internal(dx1,dy1,dx2-dx1+1,dy2-dy1+1,sx,sy); +} + +void gr_opengl2_aabitmap(int x, int y) +{ + int w, h; + + bm_get_info( gr_screen.current_bitmap, &w, &h, NULL ); + int dx1=x, dx2=x+w-1; + int dy1=y, dy2=y+h-1; + int sx=0, sy=0; + + if ((dx1 > gr_screen.clip_right ) || (dx2 < gr_screen.clip_left)) return; + if ((dy1 > gr_screen.clip_bottom ) || (dy2 < gr_screen.clip_top)) return; + if ( dx1 < gr_screen.clip_left ) { sx = gr_screen.clip_left-dx1; dx1 = gr_screen.clip_left; } + if ( dy1 < gr_screen.clip_top ) { sy = gr_screen.clip_top-dy1; dy1 = gr_screen.clip_top; } + if ( dx2 > gr_screen.clip_right ) { dx2 = gr_screen.clip_right; } + if ( dy2 > gr_screen.clip_bottom ) { dy2 = gr_screen.clip_bottom; } + + if ( sx < 0 ) return; + if ( sy < 0 ) return; + if ( sx >= w ) return; + if ( sy >= h ) return; + + // Draw bitmap bm[sx,sy] into (dx1,dy1)-(dx2,dy2) + gr_opengl2_aabitmap_ex(dx1,dy1,dx2-dx1+1,dy2-dy1+1,sx,sy); +} + +void opengl2_error_check(const char *name, int lno) +{ + GLenum error = GL_NO_ERROR; + + do { + error = glGetError(); + + if (error != GL_NO_ERROR) { + nprintf(("Warning", "!!DEBUG!! OpenGL Error: %d at %s:%d\n", error, name, lno)); + } + } while (error != GL_NO_ERROR); +} + + +void gr_opengl2_string(int sx, int sy, const char *s) +{ + int width, spacing, letter; + int x, y; + int rb_offset; + float u_scale, v_scale; + float u0, u1, v0, v1; + float x1, x2, y1, y2; + int bw, bh; + float fbw, fbh; + + if ( !Current_font ) { + return; + } + + gr_set_bitmap(Current_font->bitmap_id, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1); + + if ( !opengl2_tcache_set( gr_screen.current_bitmap, TCACHE_TYPE_AABITMAP, &u_scale, &v_scale, 0 ) ) { + // Couldn't set texture + mprintf(( "WARNING: Error setting aabitmap texture!\n" )); + return; + } + + bm_get_info( gr_screen.current_bitmap, &bw, &bh ); + + fbw = 1.0f / i2fl(bw); + fbh = 1.0f / i2fl(bh); + + opengl2_set_state( TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE ); + + // don't want to create a super huge buffer size (i.e. credits text) + const int alocsize = 320; // 80 characters max per render call + opengl_alloc_render_buffer(alocsize); + + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(rb_t), &render_buffer[0].x); + glEnableVertexAttribArray(1); + + float r, g, b, a; + gr_get_colorf(&r, &g, &b, &a); + glVertexAttrib4f(2, r, g, b, a); + + glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(rb_t), &render_buffer[0].u); + glEnableVertexAttribArray(3); + + + y = sy; + + if (sx==0x8000) { //centered + x = get_centered_x(s); + } else { + x = sx; + } + + spacing = 0; + rb_offset = 0; + + while (*s) { + x += spacing; + + while (*s== '\n' ) { + s++; + y += Current_font->h; + if (sx==0x8000) { //centered + x = get_centered_x(s); + } else { + x = sx; + } + } + if (*s == 0 ) break; + + letter = get_char_width(s[0],s[1],&width,&spacing); + s++; + + //not in font, draw as space + if (letter<0) { + continue; + } + + int xd, yd, xc, yc; + int wc, hc; + + // Check if this character is totally clipped + if ( x + width < gr_screen.clip_left ) continue; + if ( y + Current_font->h < gr_screen.clip_top ) continue; + if ( x > gr_screen.clip_right ) continue; + if ( y > gr_screen.clip_bottom ) continue; + + xd = yd = 0; + if ( x < gr_screen.clip_left ) xd = gr_screen.clip_left - x; + if ( y < gr_screen.clip_top ) yd = gr_screen.clip_top - y; + xc = x+xd; + yc = y+yd; + + wc = width - xd; hc = Current_font->h - yd; + if ( xc + wc > gr_screen.clip_right ) wc = gr_screen.clip_right - xc; + if ( yc + hc > gr_screen.clip_bottom ) hc = gr_screen.clip_bottom - yc; + + if ( wc < 1 ) continue; + if ( hc < 1 ) continue; + + float u = i2fl(Current_font->bm_u[letter] + xd); + float v = i2fl(Current_font->bm_v[letter] + yd); + + x1 = i2fl(xc + gr_screen.offset_x); + y1 = i2fl(yc + gr_screen.offset_y); + x2 = x1 + i2fl(wc); + y2 = y1 + i2fl(hc); + + u0 = u_scale * (u * fbw); + v0 = v_scale * (v * fbh); + + u1 = u_scale * ((u+i2fl(wc)) * fbw); + v1 = v_scale * ((v+i2fl(hc)) * fbh); + + // maybe go ahead and draw + if (rb_offset == alocsize) { + glDrawArrays(GL_TRIANGLE_STRIP, 0, rb_offset); + rb_offset = 0; + } + + render_buffer[rb_offset].x = x1; + render_buffer[rb_offset].y = y1; + render_buffer[rb_offset].u = u0; + render_buffer[rb_offset].v = v0; + ++rb_offset; + + render_buffer[rb_offset].x = x1; + render_buffer[rb_offset].y = y2; + render_buffer[rb_offset].u = u0; + render_buffer[rb_offset].v = v1; + ++rb_offset; + + render_buffer[rb_offset].x = x2; + render_buffer[rb_offset].y = y1; + render_buffer[rb_offset].u = u1; + render_buffer[rb_offset].v = v0; + ++rb_offset; + + render_buffer[rb_offset].x = x2; + render_buffer[rb_offset].y = y2; + render_buffer[rb_offset].u = u1; + render_buffer[rb_offset].v = v1; + ++rb_offset; + } + + if (rb_offset) { + glDrawArrays(GL_TRIANGLE_STRIP, 0, rb_offset); + } + + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(3); +} + +void gr_opengl2_line(int x1, int y1, int x2, int y2) +{ + +} + +void gr_opengl2_aaline(vertex *v1, vertex *v2) +{ + gr_opengl2_line( fl2i(v1->sx), fl2i(v1->sy), fl2i(v2->sx), fl2i(v2->sy) ); +} + +void gr_opengl2_gradient(int x1, int y1, int x2, int y2) +{ + +} + +void gr_opengl2_circle(int xc, int yc, int d) +{ + int p,x, y, r; + + r = d/2; + p=3-d; + x=0; + y=r; + + // Big clip + if ( (xc+r) < gr_screen.clip_left ) return; + if ( (xc-r) > gr_screen.clip_right ) return; + if ( (yc+r) < gr_screen.clip_top ) return; + if ( (yc-r) > gr_screen.clip_bottom ) return; + + while(xsx; y0 = va->sy; + x1 = vb->sx; y1 = vb->sy; + + xmin = i2fl(gr_screen.clip_left); ymin = i2fl(gr_screen.clip_top); + xmax = i2fl(gr_screen.clip_right); ymax = i2fl(gr_screen.clip_bottom); + + u0 = va->u; v0 = va->v; + u1 = vb->u; v1 = vb->v; + + // Check for obviously offscreen bitmaps... + if ( (y1<=y0) || (x1<=x0) ) return; + if ( (x1xmax) ) return; + if ( (y1ymax) ) return; + + clipped_u0 = u0; clipped_v0 = v0; + clipped_u1 = u1; clipped_v1 = v1; + + clipped_x0 = x0; clipped_y0 = y0; + clipped_x1 = x1; clipped_y1 = y1; + + // Clip the left, moving u0 right as necessary + if ( x0 < xmin ) { + clipped_u0 = FIND_SCALED_NUM(xmin,x0,x1,u0,u1); + clipped_x0 = xmin; + } + + // Clip the right, moving u1 left as necessary + if ( x1 > xmax ) { + clipped_u1 = FIND_SCALED_NUM(xmax,x0,x1,u0,u1); + clipped_x1 = xmax; + } + + // Clip the top, moving v0 down as necessary + if ( y0 < ymin ) { + clipped_v0 = FIND_SCALED_NUM(ymin,y0,y1,v0,v1); + clipped_y0 = ymin; + } + + // Clip the bottom, moving v1 up as necessary + if ( y1 > ymax ) { + clipped_v1 = FIND_SCALED_NUM(ymax,y0,y1,v0,v1); + clipped_y1 = ymax; + } + + dx0 = fl2i(clipped_x0); dx1 = fl2i(clipped_x1); + dy0 = fl2i(clipped_y0); dy1 = fl2i(clipped_y1); + + if (dx1<=dx0) return; + if (dy1<=dy0) return; + + //============= DRAW IT ===================== + + vertex v[4]; + vertex *vl[4]; + + vl[0] = &v[0]; + v[0].sx = clipped_x0; + v[0].sy = clipped_y0; + v[0].sw = va->sw; + v[0].z = va->z; + v[0].u = clipped_u0; + v[0].v = clipped_v0; + + vl[1] = &v[1]; + v[1].sx = clipped_x1; + v[1].sy = clipped_y0; + v[1].sw = va->sw; + v[1].z = va->z; + v[1].u = clipped_u1; + v[1].v = clipped_v0; + + vl[2] = &v[2]; + v[2].sx = clipped_x1; + v[2].sy = clipped_y1; + v[2].sw = va->sw; + v[2].z = va->z; + v[2].u = clipped_u1; + v[2].v = clipped_v1; + + vl[3] = &v[3]; + v[3].sx = clipped_x0; + v[3].sy = clipped_y1; + v[3].sw = va->sw; + v[3].z = va->z; + v[3].u = clipped_u0; + v[3].v = clipped_v1; + + opengl2_tmapper_internal( 4, vl, TMAP_FLAG_TEXTURED, 1 ); +} diff --git a/src/graphics/grgl2shader.cpp b/src/graphics/grgl2shader.cpp new file mode 100644 index 0000000..2784897 --- /dev/null +++ b/src/graphics/grgl2shader.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (C) Volition, Inc. 1999. All rights reserved. + * + * All source code herein is the property of Volition, Inc. You may not sell + * or otherwise commercially exploit the source or things you created based on + * the source. + */ + +#include "SDL_opengles2.h" + +#include "pstypes.h" +#include "gropengl.h" +#include "gropenglinternal.h" +#include "grgl2.h" + + +GLuint basicTexture = 0; + + +static const char vert_src[] = + "uniform mat4 vOrtho;\n" + "attribute vec4 vPosition;\n" + "attribute vec4 vColor;\n" + "attribute vec2 vTexCoord;\n" + "varying vec4 colorVar;\n" + "varying vec2 texCoordVar;\n" + "void main()\n" + "{\n" + " gl_Position = vOrtho * vPosition;\n" + " colorVar = vColor;\n" + " texCoordVar = vTexCoord;\n" + "}\n"; + +static const char frag_src[] = + "precision mediump float;\n" + "uniform sampler2D texture;\n" + "varying vec4 colorVar;\n" + "varying vec2 texCoordVar;\n" + "void main()\n" + "{\n" + " gl_FragColor = colorVar * texture2D(texture, texCoordVar);\n" + "}\n"; + + +static GLuint opengl2_create_shader(const char *src, GLenum type) +{ + GLuint shader; + GLint compiled; + + shader = glCreateShader(type); + + if ( !shader ) { + return 0; + } + + glShaderSource(shader, 1, &src, NULL); + + glCompileShader(shader); + + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + + if ( !compiled ) { + GLint len = 0; + + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len); + + if (len > 1) { + char *log = (char *) malloc(sizeof(char) * len); + + glGetShaderInfoLog(shader, len, NULL, log); + nprintf(("OpenGL", "Error compiling shader:\n%s\n", log)); + + free(log); + } + + glDeleteShader(shader); + + return 0; + } + + return shader; +} +/* +static GLuint opengl2_create_program(GLuint vert, GLuint frag) +{ + GLuint program; + GLint linked; + + program = glCreateProgram(); + + if ( !program ) { + return 0; + } + + glAttachShader(program, vert); + glAttachShader(program, frag); + + glLinkProgram(program); + + glGetProgramiv(program, GL_LINK_STATUS, &linked); + + if ( !linked ) { + GLint len = 0; + + glGetProgramiv(basicTexture, GL_INFO_LOG_LENGTH, &len); + + if (len > 1) { + char *log = (char *) malloc(sizeof(char) * len); + + glGetProgramInfoLog(basicTexture, len, NULL, log); + nprintf(("OpenGL", "Error linking program:\n%s\n", log)); + + free(log); + } + + glDeleteProgram(basicTexture); + + return 0; + } + + return program; +} +*/ +int opengl2_shader_init() +{ + GLint linked; + + GLuint vert_shader = opengl2_create_shader(vert_src, GL_VERTEX_SHADER); + GLuint frag_shader = opengl2_create_shader(frag_src, GL_FRAGMENT_SHADER); + + basicTexture = glCreateProgram(); + + if ( !basicTexture ) { + return 0; + } + + glAttachShader(basicTexture, vert_shader); + glAttachShader(basicTexture, frag_shader); + + glBindAttribLocation(basicTexture, 1, "vPosition"); + glBindAttribLocation(basicTexture, 2, "vColor"); + glBindAttribLocation(basicTexture, 3, "vTexCoord"); + + glLinkProgram(basicTexture); + + glGetProgramiv(basicTexture, GL_LINK_STATUS, &linked); + + if ( !linked ) { + GLint len = 0; + + glGetProgramiv(basicTexture, GL_INFO_LOG_LENGTH, &len); + + if (len > 1) { + char *log = (char *) malloc(sizeof(char) * len); + + glGetProgramInfoLog(basicTexture, len, NULL, log); + nprintf(("OpenGL", "Error linking program:\n%s\n", log)); + + free(log); + } + + glDeleteProgram(basicTexture); + + return 0; + } + + glUseProgram(basicTexture); + + return 1; +} + +void opengl2_shader_cleanup() +{ + if (basicTexture) { + glDeleteProgram(basicTexture); + basicTexture = 0; + } +} diff --git a/src/graphics/grgl2texture.cpp b/src/graphics/grgl2texture.cpp new file mode 100644 index 0000000..fe30395 --- /dev/null +++ b/src/graphics/grgl2texture.cpp @@ -0,0 +1,517 @@ +/* + * Copyright (C) Volition, Inc. 1999. All rights reserved. + * + * All source code herein is the property of Volition, Inc. You may not sell + * or otherwise commercially exploit the source or things you created based on + * the source. + */ + +#include "SDL_opengles2.h" + +#include "pstypes.h" +#include "2d.h" +#include "gropengl.h" +#include "gropenglinternal.h" +#include "grgl2.h" +#include "bmpman.h" +#include "grinternal.h" +#include "systemvars.h" +#include "osregistry.h" + + +static bool vram_full = false; + +struct tcache_slot_opengl2 { + GLuint texture_handle; + float u_scale; + float v_scale; + int bitmap_id; + int size; + int used_this_frame; + int time_created; + int is_mipmaped; + ushort w; + ushort h; + + gr_texture_source texture_mode; +}; + +static tcache_slot_opengl2 *Textures = NULL; + +static tcache_slot_opengl2 *GL_bound_texture; + +static int GL_frame_count = 0; +static int GL_last_bitmap_id = -1; +static int GL_last_detail = -1; +static int GL_last_bitmap_type = -1; +static int GL_should_preload = 0; + +static ubyte GL_xlat[256] = { 0 }; + +extern int Gr_textures_in; +extern int bm_get_cache_slot( int bitmap_id, int separate_ani_frames ); + +extern bool Use_mipmaps; + + +void opengl2_set_texture_state(gr_texture_source ts) +{ + if (ts == TEXTURE_SOURCE_NONE) { + GL_bound_texture = NULL; + + glBindTexture(GL_TEXTURE_2D, 0); + opengl2_tcache_set(-1, -1, NULL, NULL, 0); + } else if (GL_bound_texture && GL_bound_texture->texture_mode != ts) { + switch (ts) { + case TEXTURE_SOURCE_DECAL: + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + + case TEXTURE_SOURCE_NO_FILTERING: { + if (GL_bound_texture->is_mipmaped) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + break; + } + + default: + break; + } + + GL_bound_texture->texture_mode = ts; + } +} + +void opengl2_tcache_init() +{ + GL_should_preload = os_config_read_uint("Video", "PreloadTextures", 1); + + Textures = (tcache_slot_opengl2 *) malloc(MAX_BITMAPS * sizeof(tcache_slot_opengl2)); + + if (Textures == NULL) { + exit(1); + } + + SDL_assert(gr_screen.use_sections == 0); + + SDL_zerop(Textures); + + for (int i = 0; i < MAX_BITMAPS; i++) { + Textures[i].bitmap_id = -1; + } + + GL_last_detail = Detail.hardware_textures; + GL_last_bitmap_id = -1; + GL_last_bitmap_type = -1; + + SDL_zero(GL_xlat); +} + +static int opengl2_free_texture(tcache_slot_opengl2 *t) +{ + if (t->bitmap_id < 0) { + return 1; + } + + // if I have been used this frame, bail + if (t->used_this_frame == GL_frame_count) { + return 0; + } + + glDeleteTextures(1, &t->texture_handle); + + if (GL_last_bitmap_id == t->bitmap_id) { + GL_last_bitmap_id = -1; + } + + Gr_textures_in -= t->size; + + t->texture_handle = 0; + t->bitmap_id = -1; + t->used_this_frame = 0; + t->size = 0; + t->is_mipmaped = 0; + + return 1; +} + +void opengl2_tcache_flush() +{ + for (int i = 0; i < MAX_BITMAPS; i++) { + opengl2_free_texture(&Textures[i]); + } + + if (Gr_textures_in != 0) { + mprintf(("WARNING: VRAM is at %d instead of zero after flushing!\n", Gr_textures_in)); + Gr_textures_in = 0; + } + + GL_last_bitmap_id = -1; + + vram_full = false; +} + +void opengl2_tcache_cleanup() +{ + opengl2_tcache_flush(); + + if (Textures) { + free(Textures); + Textures = NULL; + } +} + +void opengl2_tcache_frame() +{ + GL_last_bitmap_id = -1; + GL_frame_count++; + + if (vram_full) { + opengl2_tcache_flush(); + vram_full = false; + } +} + +static int opengl2_create_texture_sub(int bitmap_handle, int bitmap_type, bitmap *bmp, tcache_slot_opengl2 *t, int tex_w, int tex_h, bool reload, bool resize, int fail_on_full) +{ + // bogus + if ( (bmp == NULL) || (t == NULL) ) { + return 0; + } + + if (t->used_this_frame == GL_frame_count) { + mprintf(("ARGHH!!! Texture already used this frame! Cannot free it!\n")); + return 0; + } + + if ( !reload ) { + if ( !opengl2_free_texture(t) ) { + return 0; + } + + glGenTextures(1, &t->texture_handle); + + if ( !t->texture_handle ) { + nprintf(("Error", "!!DEBUG!! t->texture_handle == 0")); + return 0; + } + } + + t->u_scale = 1.0f; + t->v_scale = 1.0f; + + t->texture_mode = TEXTURE_SOURCE_NO_FILTERING; + + glBindTexture(GL_TEXTURE_2D, t->texture_handle); + + 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); + + ubyte *bmp_data = (ubyte*)bmp->data; + ubyte *texmem = NULL, *texmemp; + int i, j; + int size = 0; + + switch (bitmap_type) { + case TCACHE_TYPE_AABITMAP: { + texmem = (ubyte *) malloc(tex_w * tex_h); + texmemp = texmem; + + for (i = 0; i < tex_h; i++) { + for (j = 0; j < tex_w; j++) { + if ( (i < bmp->h) && (j < bmp->w) ) { + *texmemp++ = GL_xlat[bmp_data[i*bmp->w+j]]; + } else { + *texmemp++ = 0; + } + } + } + + size = tex_w * tex_h; + + if (reload) { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_ALPHA, GL_UNSIGNED_BYTE, texmem); + } else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_w, tex_h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texmem); + } + + free(texmem); + + break; + } + + case TCACHE_TYPE_BITMAP_INTERFACE: + case TCACHE_TYPE_BITMAP_SECTION: { + size = tex_w * tex_h * 2; + + if (reload) { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, bmp_data); + } else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, bmp_data); + } + + break; + } + + default: { + if (resize) { + texmem = (ubyte *) malloc(tex_w * tex_h * 2); + texmemp = texmem; + + SDL_assert(texmem); + + fix u = 0, utmp, v = 0, du, dv; + + du = ((bmp->w - 1) * F1_0) / tex_w; + dv = ((bmp->h - 1) * F1_0) / tex_h; + + for (j = 0; j < tex_h; j++) { + utmp = u; + + for (i = 0; i < tex_w; i++) { + *texmemp++ = bmp_data[(f2i(v)*bmp->w+f2i(utmp))*2+0]; + *texmemp++ = bmp_data[(f2i(v)*bmp->w+f2i(utmp))*2+1]; + + utmp += du; + } + + v += dv; + } + } + + if (reload) { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (resize) ? texmem : bmp_data); + } else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (resize) ? texmem : bmp_data); + } + + if (texmem) { + free(texmem); + } + + if (Use_mipmaps) { + glGenerateMipmap(GL_TEXTURE_2D); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); + t->is_mipmaped = 1; + + size = fl2i(tex_w * tex_h * 2.0f * 1.3333333f); + } else { + size = tex_w * tex_h * 2; + } + + break; + } + } + + t->bitmap_id = bitmap_handle; + t->time_created = GL_frame_count; + t->used_this_frame = 0; + t->size = size; + t->w = (ushort)tex_w; + t->h = (ushort)tex_h; + + if ( !reload ) { + Gr_textures_in += t->size; + } + + return 1; +} + +static int opengl2_create_texture(int bitmap_handle, int bitmap_type, tcache_slot_opengl2 *tslot, int fail_on_full) +{ + ubyte flags = 0; + bool cull_size = false; + bool resize = false; + ubyte bpp = 16; + + switch (bitmap_type) { + case TCACHE_TYPE_AABITMAP: { + flags |= BMP_AABITMAP; + bpp = 8; + + break; + } + + case TCACHE_TYPE_NORMAL: { + flags |= BMP_TEX_OTHER; + cull_size = 1; + + break; + } + + case TCACHE_TYPE_BITMAP_INTERFACE: + case TCACHE_TYPE_XPARENT: { + flags |= BMP_TEX_XPARENT; + + break; + } + + default: + Int3(); + return 0; + } + + bitmap *bmp = bm_lock(bitmap_handle, bpp, flags); + + if (bmp == NULL) { + mprintf(("Couldn't lock bitmap %d\n", bitmap_handle)); + return 0; + } + + int max_w = bmp->w; + int max_h = bmp->h; + + if ( cull_size && (Detail.hardware_textures < 4) ) { + // if we are going to cull the size then we need to force a resize + resize = true; + + // Detail.hardware_textures goes form 0 to 4 + int val = 16 >> Detail.hardware_textures; + + max_w /= val; + max_h /= val; + } + + if ( (max_w < 1) || (max_h < 1) ) { + mprintf(("Bitmap %d is too small at %dx%d\n", bitmap_handle, max_w, max_h)); + return 0; + } + + bool reload = false; + + // see if we can reuse this slot for a new bitmap + if ( tslot->texture_handle && (tslot->bitmap_id != bitmap_handle) ) { + if ( (max_w == tslot->w) && (max_h == tslot->h) ) { + reload = true; + } + } + + // call the helper + int ret_val = opengl2_create_texture_sub(bitmap_handle, bitmap_type, bmp, tslot, max_w, max_h, reload, resize, fail_on_full); + + // unlock the bitmap + bm_unlock(bitmap_handle); + + return ret_val; +} + +int opengl2_tcache_set(int bitmap_id, int bitmap_type, float *u_scale, float *v_scale, int fail_on_full) +{ + if (bitmap_id < 0) { + GL_last_bitmap_id = -1; + + return 0; + } + + if (GL_last_detail != Detail.hardware_textures) { + opengl2_tcache_flush(); + GL_last_detail = Detail.hardware_textures; + } + + if (vram_full) { + return 0; + } + + int n = bm_get_cache_slot(bitmap_id, 1); + tcache_slot_opengl2 *t = &Textures[n]; + + if ( (GL_last_bitmap_id == bitmap_id) && (GL_last_bitmap_type == bitmap_type) && (t->bitmap_id == bitmap_id) ) { + t->used_this_frame = GL_frame_count; + + *u_scale = t->u_scale; + *v_scale = t->v_scale; + + return 1; + } + + int ret_val = 1; + + if (bitmap_id != t->bitmap_id) { + ret_val = opengl2_create_texture(bitmap_id, bitmap_type, t, fail_on_full); + } + + if (ret_val && t->texture_handle && !vram_full) { + glBindTexture(GL_TEXTURE_2D, t->texture_handle); + + *u_scale = t->u_scale; + *v_scale = t->v_scale; + + GL_bound_texture = t; + + GL_last_bitmap_id = t->bitmap_id; + GL_last_bitmap_type = bitmap_type; + + t->used_this_frame = GL_frame_count; + } else { + GL_last_bitmap_id = -1; + GL_last_bitmap_type = -1; + + GL_bound_texture = NULL; + + glBindTexture(GL_TEXTURE_2D, 0); + + return 0; + } + + return 1; +} + +void gr_opengl2_preload_init() +{ + opengl2_tcache_flush(); +} + +int gr_opengl2_preload(int bitmap_num, int is_aabitmap) +{ + if ( !GL_should_preload ) { + return 0; + } + + int bitmap_type = (is_aabitmap) ? TCACHE_TYPE_AABITMAP : TCACHE_TYPE_NORMAL; + float u_scale, v_scale; + + int retval = opengl2_tcache_set(bitmap_num, bitmap_type, &u_scale, &v_scale, 1); + + if ( !retval ) { + mprintf(("Texture upload failed bit bitmap %d!\n", bitmap_num)); + } + + return retval; +} + +void gr_opengl2_set_gamma(float) +{ + // set the alpha gamma settings (for fonts) + for (int i = 0; i < 16; i++) { + GL_xlat[i] = (ubyte)Gr_gamma_lookup[(i*255)/15]; + } + + GL_xlat[15] = GL_xlat[1]; + + // Flush any existing textures + opengl2_tcache_flush(); +} + +void gr_opengl2_release_texture(int handle) +{ + for (int i = 0; i < MAX_BITMAPS; i++) { + tcache_slot_opengl2 *t = &Textures[i]; + + if (t->bitmap_id == handle) { + t->used_this_frame = 0; + opengl2_free_texture(t); + + break; + } + } +} diff --git a/src/graphics/gropengl.cpp b/src/graphics/gropengl.cpp index b8fb918..f6e2a50 100644 --- a/src/graphics/gropengl.cpp +++ b/src/graphics/gropengl.cpp @@ -6,17 +6,21 @@ * the source. */ +#include "SDL_opengl.h" + #include "pstypes.h" #include "osregistry.h" #include "gropengl.h" -#include "grgl1.h" #include "gropenglinternal.h" +#include "grgl1.h" +#include "grgl2.h" #include "2d.h" #include "bmpman.h" #include "grinternal.h" #include "cmdline.h" #include "mouse.h" #include "osapi.h" +#include "cfile.h" bool OGL_inited = false; @@ -25,7 +29,8 @@ int GL_version = 0; SDL_Window *GL_window = NULL; SDL_GLContext GL_context; -static int FSAA = 0; +volatile int GL_activate = 0; +volatile int GL_deactivate = 0; int GL_viewport_x = 0; int GL_viewport_y = 0; @@ -93,12 +98,6 @@ void opengl_init_viewport() GL_viewport_scale_h = 1.0f; glViewport(GL_viewport_x, GL_viewport_y, GL_viewport_w, GL_viewport_h); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, GL_viewport_w, GL_viewport_h, 0, 0.0, 1.0); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); } void gr_opengl_force_windowed() @@ -122,9 +121,125 @@ void gr_opengl_toggle_fullscreen() } } +void gr_opengl_clear() +{ + glClearColor(gr_screen.current_clear_color.red / 255.0f, + gr_screen.current_clear_color.green / 255.0f, + gr_screen.current_clear_color.blue / 255.0f, 1.0f); + + glClear( GL_COLOR_BUFFER_BIT ); +} + +void gr_opengl_reset_clip() +{ + gr_screen.offset_x = 0; + gr_screen.offset_y = 0; + gr_screen.clip_left = 0; + gr_screen.clip_top = 0; + gr_screen.clip_right = gr_screen.max_w - 1; + gr_screen.clip_bottom = gr_screen.max_h - 1; + gr_screen.clip_width = gr_screen.max_w; + gr_screen.clip_height = gr_screen.max_h; + + glDisable(GL_SCISSOR_TEST); +} + +void gr_opengl_print_screen(const char *filename) +{ + char tmp[MAX_FILENAME_LEN]; + ubyte *buf = NULL; + + SDL_strlcpy( tmp, filename, SDL_arraysize(tmp) ); + SDL_strlcat( tmp, NOX(".tga"), SDL_arraysize(tmp) ); + + buf = (ubyte*)malloc(GL_viewport_w * GL_viewport_h * 3); + + if (buf == NULL) { + return; + } + + CFILE *f = cfopen(tmp, "wb", CFILE_NORMAL, CF_TYPE_ROOT); + + if (f == NULL) { + free(buf); + return; + } + + // Write the TGA header + cfwrite_ubyte( 0, f ); // IDLength; + cfwrite_ubyte( 0, f ); // ColorMapType; + cfwrite_ubyte( 2, f ); // ImageType; // 2 = 24bpp, uncompressed, 10=24bpp rle compressed + cfwrite_ushort( 0, f ); // CMapStart; + cfwrite_ushort( 0, f ); // CMapLength; + cfwrite_ubyte( 0, f ); // CMapDepth; + cfwrite_ushort( 0, f ); // XOffset; + cfwrite_ushort( 0, f ); // YOffset; + cfwrite_ushort( (ushort)GL_viewport_w, f ); // Width; + cfwrite_ushort( (ushort)GL_viewport_h, f ); // Height; + cfwrite_ubyte( 24, f ); //PixelDepth; + cfwrite_ubyte( 0, f ); //ImageDesc; + + memset(buf, 0, GL_viewport_w * GL_viewport_h * 3); + + glReadPixels(GL_viewport_x, GL_viewport_y, GL_viewport_w, GL_viewport_h, GL_RGB, GL_UNSIGNED_BYTE, buf); + + cfwrite(buf, GL_viewport_w * GL_viewport_h * 3, 1, f); + + cfclose(f); + + free(buf); +} + +uint gr_opengl_lock() +{ + return 1; +} + +void gr_opengl_unlock() +{ +} + +void gr_opengl_zbias(int bias) +{ + if (bias) { + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(0.0f, GLfloat(-bias)); + } else { + glDisable(GL_POLYGON_OFFSET_FILL); + } +} + +void gr_opengl_set_cull(int cull) +{ + if (cull) { + glEnable (GL_CULL_FACE); + glFrontFace (GL_CCW); + } else { + glDisable (GL_CULL_FACE); + } +} + +void gr_opengl_activate(int active) +{ + if (active) { + GL_activate++; + + // don't grab key/mouse if cmdline says so or if we're fullscreen + // if(!Cmdline_no_grab && !(SDL_GetVideoSurface()->flags & SDL_FULLSCREEN)) { + // SDL_WM_GrabInput(SDL_GRAB_ON); + // } + } else { + GL_deactivate++; + + // let go of mouse/keyboard + // SDL_WM_GrabInput(SDL_GRAB_OFF); + } +} + void gr_opengl_cleanup() { opengl1_cleanup(); + opengl2_cleanup(); opengl_free_render_buffer(); @@ -153,22 +268,6 @@ void gr_opengl_init() Error(LOCATION, "Couldn't init SDL: %s", SDL_GetError()); } - int a = 1, r = 5, g = 5, b = 5, bpp = 16, db = 1; - - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, r); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, g); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, b); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, a); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, bpp); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, db); - - FSAA = os_config_read_uint("Video", "AntiAlias", 0); - - if (FSAA) { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, FSAA); - } - GL_window = SDL_CreateWindow(os_get_title(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, gr_screen.max_w, gr_screen.max_h, SDL_WINDOW_OPENGL); @@ -179,44 +278,44 @@ void gr_opengl_init() os_set_window(GL_window); - GL_context = SDL_GL_CreateContext(GL_window); - - const char *gl_version = (const char*)glGetString(GL_VERSION); - int v_major = 0, v_minor = 0; + int a = 1, r = 5, g = 5, b = 5, bpp = 16; + int FSAA = os_config_read_uint("Video", "AntiAlias", 0); - sscanf(gl_version, "%d.%d", &v_major, &v_minor); - - GL_version = (v_major * 10) + v_minor; + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, r); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, g); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, b); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, a); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, bpp); - // version check, require 1.2+ for sake of simplicity - if (GL_version < 12) { - Error(LOCATION, "Minimum OpenGL version is 1.2!"); + if (FSAA) { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, FSAA); } - mprintf((" Vendor : %s\n", glGetString(GL_VENDOR))); - mprintf((" Renderer : %s\n", glGetString(GL_RENDERER))); - mprintf((" Version : %s\n", gl_version)); - - // initial viewport setup - opengl_init_viewport(); + int rc = 1; - // set up generic variables before further init() calls - opengl_set_variables(); + // try GL 2 first, then fall back to GL 1 + if ( !opengl2_init() ) { + rc = opengl1_init(); + } - // main GL init - opengl1_init(); + if ( !rc ) { + Error(LOCATION, "Unable to initialize OpenGL renderer!\n"); + } - mprintf((" Attributes requested : ARGB %d%d%d%d, BPP %d, DB %d, AA %d\n", a, r, g, b, bpp, db, FSAA)); + mprintf((" Attributes requested : ARGB %d%d%d%d, BPP %d, AA %d\n", + a, r, g, b, bpp, FSAA)); SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &r); SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &g); SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &b); SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &a); SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &bpp); - SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &db); SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &FSAA); - mprintf((" Attributes received : ARGB %d%d%d%d, BPP %d, DB %d, AA %d\n", a, r, g, b, bpp, db, FSAA)); + mprintf((" Attributes received : ARGB %d%d%d%d, BPP %d, AA %d\n", + a, r, g, b, bpp, FSAA)); + mprintf(("\n")); SDL_DisableScreenSaver(); SDL_ShowCursor(0); @@ -229,9 +328,6 @@ void gr_opengl_init() os_poll(); } - mprintf(("\n")); - - switch (bpp) { case 15: case 16: diff --git a/src/graphics/grwxgl.cpp b/src/graphics/grwxgl.cpp index 451cd90..7fa9a96 100644 --- a/src/graphics/grwxgl.cpp +++ b/src/graphics/grwxgl.cpp @@ -6,12 +6,14 @@ * the source. */ +#include "SDL_opengl.h" + #include "pstypes.h" #include "2d.h" #include "grwxgl.h" #include "gropengl.h" -#include "grgl1.h" #include "gropenglinternal.h" +#include "grgl1.h" #include "grinternal.h" #include "mouse.h" @@ -27,9 +29,9 @@ static void wxgl_init_func_pointers() { gr_screen.gf_flip = gr_wxgl_flip; gr_screen.gf_set_clip = gr_opengl1_set_clip; - gr_screen.gf_reset_clip = gr_opengl1_reset_clip; + gr_screen.gf_reset_clip = gr_opengl_reset_clip; - gr_screen.gf_clear = gr_opengl1_clear; + gr_screen.gf_clear = gr_opengl_clear; gr_screen.gf_aabitmap = gr_opengl1_aabitmap; gr_screen.gf_aabitmap_ex = gr_opengl1_aabitmap_ex; @@ -47,7 +49,7 @@ static void wxgl_init_func_pointers() gr_screen.gf_gradient = gr_opengl1_gradient; - gr_screen.gf_print_screen = gr_opengl1_print_screen; + gr_screen.gf_print_screen = gr_opengl_print_screen; gr_screen.gf_fade_in = gr_opengl1_fade_in; gr_screen.gf_fade_out = gr_opengl1_fade_out; @@ -65,21 +67,21 @@ static void wxgl_init_func_pointers() gr_screen.gf_set_gamma = gr_opengl1_set_gamma; - gr_screen.gf_lock = gr_opengl1_lock; - gr_screen.gf_unlock = gr_opengl1_unlock; + gr_screen.gf_lock = gr_opengl_lock; + gr_screen.gf_unlock = gr_opengl_unlock; gr_screen.gf_fog_set = gr_opengl1_fog_set; gr_screen.gf_get_region = gr_opengl1_get_region; - gr_screen.gf_set_cull = gr_opengl1_set_cull; + gr_screen.gf_set_cull = gr_opengl_set_cull; gr_screen.gf_cross_fade = gr_opengl1_cross_fade; gr_screen.gf_preload_init = gr_opengl1_preload_init; gr_screen.gf_preload = gr_opengl1_preload; - gr_screen.gf_zbias = gr_opengl1_zbias; + gr_screen.gf_zbias = gr_opengl_zbias; gr_screen.gf_force_windowed = gr_opengl_force_windowed; gr_screen.gf_force_fullscreen = gr_opengl_force_fullscreen; @@ -87,7 +89,7 @@ static void wxgl_init_func_pointers() gr_screen.gf_set_viewport = gr_wxgl_set_viewport; - gr_screen.gf_activate = gr_opengl1_activate; + gr_screen.gf_activate = gr_opengl_activate; gr_screen.gf_release_texture = gr_opengl1_release_texture; } @@ -118,7 +120,7 @@ static void wxgl_init() wxgl_init_func_pointers(); opengl1_tcache_init(); - gr_opengl1_clear(); + gr_opengl_clear(); GL_one_inited = 1; diff --git a/src/movie/mveplayer.cpp b/src/movie/mveplayer.cpp index 7e0c9d6..124e2b4 100644 --- a/src/movie/mveplayer.cpp +++ b/src/movie/mveplayer.cpp @@ -33,6 +33,8 @@ * $NoKeywords: $ */ +#include "SDL_opengl.h" + #include "pstypes.h" #include "mvelib.h" #include "movie.h" -- 2.39.2