Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
  3.  * It is copyright by its individual contributors, as recorded in the
  4.  * project's Git history.  See COPYING.txt at the top level for license
  5.  * terms and a link to the Git history.
  6.  */
  7. /*
  8.  *
  9.  * Graphics support functions for OpenGL.
  10.  *
  11.  */
  12.  
  13. #include "dxxsconf.h"
  14. #include <stdexcept>
  15. #include <tuple>
  16. #ifdef _WIN32
  17. #include <windows.h>
  18. #include <stddef.h>
  19. #endif
  20. #if defined(__APPLE__) && defined(__MACH__)
  21. #include <OpenGL/gl.h>
  22. #include <OpenGL/glu.h>
  23. #else
  24. #if DXX_USE_OGLES
  25. #include <GLES/gl.h>
  26. #else
  27. #include <GL/gl.h>
  28. #include <GL/glu.h>
  29. #endif
  30. #endif
  31. #include <string.h>
  32. #include <math.h>
  33. #include <stdio.h>
  34.  
  35. #include "3d.h"
  36. #include "piggy.h"
  37. #include "common/3d/globvars.h"
  38. #include "dxxerror.h"
  39. #include "texmap.h"
  40. #include "palette.h"
  41. #include "rle.h"
  42. #include "console.h"
  43. #include "config.h"
  44. #include "u_mem.h"
  45.  
  46. #include "segment.h"
  47. #include "textures.h"
  48. #include "texmerge.h"
  49. #include "effects.h"
  50. #include "weapon.h"
  51. #include "powerup.h"
  52. #include "laser.h"
  53. #include "player.h"
  54. #include "robot.h"
  55. #include "gamefont.h"
  56. #include "byteutil.h"
  57. #include "internal.h"
  58. #include "gauges.h"
  59. #include "playsave.h"
  60. #include "object.h"
  61. #include "args.h"
  62.  
  63. #include "compiler-range_for.h"
  64. #include "d_range.h"
  65. #include "d_zip.h"
  66. #include "partial_range.h"
  67.  
  68. #include <algorithm>
  69. #include <memory>
  70. #include <utility>
  71. using std::max;
  72.  
  73. //change to 1 for lots of spew.
  74. #if 0
  75. #define glmprintf(A) con_printf A
  76. #else
  77. #define glmprintf(A)
  78. #endif
  79.  
  80. #ifndef M_PI
  81. #define M_PI 3.14159
  82. #endif
  83.  
  84. namespace {
  85.  
  86. template <unsigned G>
  87. struct enable_ogl_client_state
  88. {
  89.         enable_ogl_client_state() noexcept
  90.         {
  91.                 glEnableClientState(G);
  92.         }
  93.         ~enable_ogl_client_state() noexcept
  94.         {
  95.                 glDisableClientState(G);
  96.         }
  97. };
  98.  
  99. template <typename T, unsigned... Gs>
  100. using ogl_client_states = std::tuple<T, enable_ogl_client_state<Gs>...>;
  101.  
  102. template <typename T, std::size_t N1, std::size_t N2>
  103. union flatten_array
  104. {
  105.         std::array<T, N1 * N2> flat;
  106.         std::array<std::array<T, N1>, N2> nested;
  107.         static_assert(sizeof(flat) == sizeof(nested), "array padding error");
  108. };
  109.  
  110. }
  111.  
  112. #if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__)) || defined(__sun__) || defined(macintosh)
  113. #define cosf(a) cos(a)
  114. #define sinf(a) sin(a)
  115. #endif
  116.  
  117. namespace dcx {
  118.  
  119. static std::unique_ptr<GLubyte[]> texbuf;
  120.  
  121. unsigned last_width=~0u,last_height=~0u;
  122. int GL_TEXTURE_2D_enabled=-1;
  123.  
  124. static int r_texcount = 0, r_cachedtexcount = 0;
  125. #if DXX_USE_OGLES
  126. static int ogl_rgba_internalformat = GL_RGBA;
  127. static int ogl_rgb_internalformat = GL_RGB;
  128. #else
  129. static int ogl_rgba_internalformat = GL_RGBA8;
  130. static int ogl_rgb_internalformat = GL_RGB8;
  131. #endif
  132. static std::unique_ptr<GLfloat[]> sphere_va, circle_va, disk_va;
  133. static std::array<std::unique_ptr<GLfloat[]>, 3> secondary_lva;
  134. static int r_polyc,r_tpolyc,r_bitmapc,r_ubitbltc;
  135. #define f2glf(x) (f2fl(x))
  136.  
  137. #define OGL_BINDTEXTURE(a) glBindTexture(GL_TEXTURE_2D, a);
  138.  
  139. /* I assume this ought to be >= MAX_BITMAP_FILES in piggy.h? */
  140. static std::array<ogl_texture, 20000> ogl_texture_list;
  141. static int ogl_texture_list_cur;
  142.  
  143. /* some function prototypes */
  144.  
  145. #define GL_TEXTURE0_ARB 0x84C0
  146. static int ogl_loadtexture(const palette_array_t &, const uint8_t *data, int dxo, int dyo, ogl_texture &tex, int bm_flags, int data_format, int texfilt, bool texanis, bool edgepad) __attribute_nonnull();
  147. static void ogl_freetexture(ogl_texture &gltexture);
  148.  
  149. static void ogl_loadbmtexture(grs_bitmap &bm, bool edgepad)
  150. {
  151.         ogl_loadbmtexture_f(bm, CGameCfg.TexFilt, CGameCfg.TexAnisotropy, edgepad);
  152. }
  153.  
  154. }
  155.  
  156. #if DXX_USE_OGLES
  157. // Replacement for gluPerspective
  158. static void perspective(double fovy, double aspect, double zNear, double zFar)
  159. {
  160.         double xmin, xmax, ymin, ymax;
  161.  
  162.         glMatrixMode(GL_PROJECTION);
  163.         glLoadIdentity();
  164.  
  165.         ymax = zNear * tan(fovy * M_PI / 360.0);
  166.         ymin = -ymax;
  167.         xmin = ymin * aspect;
  168.         xmax = ymax * aspect;
  169.  
  170.         glFrustumf(xmin, xmax, ymin, ymax, zNear, zFar);
  171.         glMatrixMode(GL_MODELVIEW);
  172.         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);     
  173.         glDepthMask(GL_TRUE);
  174. }
  175. #endif
  176.  
  177. static void ogl_init_texture_stats(ogl_texture &t)
  178. {
  179.         t.prio=0.3;//default prio
  180.         t.numrend=0;
  181. }
  182.  
  183. void ogl_init_texture(ogl_texture &t, int w, int h, int flags)
  184. {
  185.         t.handle = 0;
  186. #if !DXX_USE_OGLES
  187.         if (flags & OGL_FLAG_NOCOLOR)
  188.         {
  189.                 // use GL_INTENSITY instead of GL_RGB
  190.                 if (flags & OGL_FLAG_ALPHA)
  191.                 {
  192.                         if (CGameArg.DbgGlIntensity4Ok)
  193.                         {
  194.                                 t.internalformat = GL_INTENSITY4;
  195.                                 t.format = GL_LUMINANCE;
  196.                         }
  197.                         else if (CGameArg.DbgGlLuminance4Alpha4Ok)
  198.                         {
  199.                                 t.internalformat = GL_LUMINANCE4_ALPHA4;
  200.                                 t.format = GL_LUMINANCE_ALPHA;
  201.                         }
  202.                         else if (CGameArg.DbgGlRGBA2Ok)
  203.                         {
  204.                                 t.internalformat = GL_RGBA2;
  205.                                 t.format = GL_RGBA;
  206.                         }
  207.                         else
  208.                         {
  209.                                 t.internalformat = ogl_rgba_internalformat;
  210.                                 t.format = GL_RGBA;
  211.                         }
  212.                 }
  213.                 else
  214.                 {
  215.                         // there are certainly smaller formats we could use here, but nothing needs it ATM.
  216.                         t.internalformat = ogl_rgb_internalformat;
  217.                         t.format = GL_RGB;
  218.                 }
  219.         }
  220.         else
  221.         {
  222. #endif
  223.                 if (flags & OGL_FLAG_ALPHA)
  224.                 {
  225.                         t.internalformat = ogl_rgba_internalformat;
  226.                         t.format = GL_RGBA;
  227.                 }
  228.                 else
  229.                 {
  230.                         t.internalformat = ogl_rgb_internalformat;
  231.                         t.format = GL_RGB;
  232.                 }
  233. #if !DXX_USE_OGLES
  234.         }
  235. #endif
  236.         t.wrapstate = -1;
  237.         t.lw = t.w = w;
  238.         t.h = h;
  239.         ogl_init_texture_stats(t);
  240. }
  241.  
  242. static void ogl_reset_texture(ogl_texture &t)
  243. {
  244.         ogl_init_texture(t, 0, 0, 0);
  245. }
  246.  
  247. static void ogl_reset_texture_stats_internal(void){
  248.         range_for (auto &i, ogl_texture_list)
  249.                 if (i.handle>0)
  250.                         ogl_init_texture_stats(i);
  251. }
  252.  
  253. void ogl_init_texture_list_internal(void){
  254.         ogl_texture_list_cur=0;
  255.         range_for (auto &i, ogl_texture_list)
  256.                 ogl_reset_texture(i);
  257. }
  258.  
  259. void ogl_smash_texture_list_internal(void){
  260.         sphere_va.reset();
  261.         circle_va.reset();
  262.         disk_va.reset();
  263.         secondary_lva = {};
  264.         range_for (auto &i, ogl_texture_list)
  265.         {
  266.                 if (i.handle>0){
  267.                         glDeleteTextures( 1, &i.handle );
  268.                         i.handle=0;
  269.                 }
  270.                 i.wrapstate = -1;
  271.         }
  272. }
  273.  
  274. ogl_texture* ogl_get_free_texture(void){
  275.         for (unsigned i = ogl_texture_list.size(); i--;)
  276.         {
  277.                 if (ogl_texture_list[ogl_texture_list_cur].handle<=0 && ogl_texture_list[ogl_texture_list_cur].w==0)
  278.                         return &ogl_texture_list[ogl_texture_list_cur];
  279.                 if (++ogl_texture_list_cur >= ogl_texture_list.size())
  280.                         ogl_texture_list_cur=0;
  281.         }
  282.         Error("OGL: texture list full!\n");
  283. }
  284.  
  285. static void ogl_texture_stats(void)
  286. {
  287.         int used = 0, usedother = 0, usedidx = 0, usedrgb = 0, usedrgba = 0;
  288.         int databytes = 0, truebytes = 0, datatexel = 0, truetexel = 0;
  289.         int prio0=0,prio1=0,prio2=0,prio3=0,prioh=0;
  290.         GLint idx, r, g, b, a, dbl, depth;
  291.         int res, colorsize, depthsize;
  292.         range_for (auto &i, ogl_texture_list)
  293.         {
  294.                 if (i.handle>0){
  295.                         used++;
  296.                         datatexel+=i.w*i.h;
  297.                         truetexel+=i.tw*i.th;
  298.                         databytes+=i.bytesu;
  299.                         truebytes+=i.bytes;
  300.                         if (i.prio<0.299)prio0++;
  301.                         else if (i.prio<0.399)prio1++;
  302.                         else if (i.prio<0.499)prio2++;
  303.                         else if (i.prio<0.599)prio3++;
  304.                         else prioh++;
  305.                         if (i.format == GL_RGBA)
  306.                                 usedrgba++;
  307.                         else if (i.format == GL_RGB)
  308.                                 usedrgb++;
  309. #if !DXX_USE_OGLES
  310.                         else if (i.format == GL_COLOR_INDEX)
  311.                                 usedidx++;
  312. #endif
  313.                         else
  314.                                 usedother++;
  315.                 }
  316.         }
  317.  
  318.         res = SWIDTH * SHEIGHT;
  319. #if !DXX_USE_OGLES
  320.         glGetIntegerv(GL_INDEX_BITS, &idx);
  321. #else
  322.         idx=16;
  323. #endif
  324.         glGetIntegerv(GL_RED_BITS, &r);
  325.         glGetIntegerv(GL_GREEN_BITS, &g);
  326.         glGetIntegerv(GL_BLUE_BITS, &b);
  327.         glGetIntegerv(GL_ALPHA_BITS, &a);
  328. #if !DXX_USE_OGLES
  329.         glGetIntegerv(GL_DOUBLEBUFFER, &dbl);
  330. #else
  331.         dbl=1;
  332. #endif
  333.         dbl += 1;
  334.         glGetIntegerv(GL_DEPTH_BITS, &depth);
  335.         gr_set_default_canvas();
  336.         auto &canvas = *grd_curcanv;
  337.         const auto &game_font = *GAME_FONT;
  338.         gr_set_fontcolor(canvas, BM_XRGB(255, 255, 255), -1);
  339.         colorsize = (idx * res * dbl) / 8;
  340.         depthsize = res * depth / 8;
  341.         const auto &&fspacx2 = FSPACX(2);
  342.         const auto &&fspacy1 = FSPACY(1);
  343.         const auto &&line_spacing = LINE_SPACING(game_font, game_font);
  344.         gr_printf(canvas, game_font, fspacx2, fspacy1, "%i flat %i tex %i bitmaps", r_polyc, r_tpolyc, r_bitmapc);
  345.         gr_printf(canvas, game_font, fspacx2, fspacy1 + line_spacing, "%i(%i,%i,%i,%i) %iK(%iK wasted) (%i postcachedtex)", used, usedrgba, usedrgb, usedidx, usedother, truebytes / 1024, (truebytes - databytes) / 1024, r_texcount - r_cachedtexcount);
  346.         gr_printf(canvas, game_font, fspacx2, fspacy1 + (line_spacing * 2), "%ibpp(r%i,g%i,b%i,a%i)x%i=%iK depth%i=%iK", idx, r, g, b, a, dbl, colorsize / 1024, depth, depthsize / 1024);
  347.         gr_printf(canvas, game_font, fspacx2, fspacy1 + (line_spacing * 3), "total=%iK", (colorsize + depthsize + truebytes) / 1024);
  348. }
  349.  
  350. static void ogl_bindbmtex(grs_bitmap &bm, bool edgepad){
  351.         if (bm.gltexture==NULL || bm.gltexture->handle<=0)
  352.                 ogl_loadbmtexture(bm, edgepad);
  353.         OGL_BINDTEXTURE(bm.gltexture->handle);
  354.         bm.gltexture->numrend++;
  355. }
  356.  
  357. //gltexture MUST be bound first
  358. static void ogl_texwrap(ogl_texture *const gltexture, const int state)
  359. {
  360.         if (gltexture->wrapstate != state || gltexture->numrend < 1)
  361.         {
  362.                 gltexture->wrapstate = state;
  363.                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, state);
  364.                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, state);
  365.         }
  366. }
  367.  
  368. //crude texture precaching
  369. //handles: powerups, walls, weapons, polymodels, etc.
  370. //it is done with the horrid do_special_effects kludge so that sides that have to be texmerged and have animated textures will be correctly cached.
  371. //similarly, with the objects(esp weapons), we could just go through and cache em all instead, but that would get ones that might not even be on the level
  372. //TODO: doors
  373.  
  374. void ogl_cache_polymodel_textures(const unsigned model_num)
  375. {
  376.         auto &Polygon_models = LevelSharedPolygonModelState.Polygon_models;
  377.         if (model_num >= Polygon_models.size())
  378.                 return;
  379.         const auto &po = Polygon_models[model_num];
  380.         unsigned i = po.first_texture;
  381.         const unsigned last_texture = i + po.n_textures;
  382.         for (; i != last_texture; ++i)
  383.         {
  384.                 auto &objbitmap = ObjBitmaps[ObjBitmapPtrs[i]];
  385.                 PIGGY_PAGE_IN(objbitmap);
  386.                 ogl_loadbmtexture(GameBitmaps[objbitmap.index], 1);
  387.         }
  388. }
  389.  
  390. static void ogl_cache_vclip_textures(const vclip &vc)
  391. {
  392.         range_for (auto &i, partial_const_range(vc.frames, vc.num_frames))
  393.         {
  394.                 PIGGY_PAGE_IN(i);
  395.                 ogl_loadbmtexture(GameBitmaps[i.index], 0);
  396.         }
  397. }
  398.  
  399. static void ogl_cache_vclipn_textures(const d_vclip_array &Vclip, const unsigned i)
  400. {
  401.         if (i < Vclip.size())
  402.                 ogl_cache_vclip_textures(Vclip[i]);
  403. }
  404.  
  405. static void ogl_cache_weapon_textures(const d_vclip_array &Vclip, const weapon_info_array &Weapon_info, const unsigned weapon_type)
  406. {
  407.         if (weapon_type >= Weapon_info.size())
  408.                 return;
  409.         const auto &w = Weapon_info[weapon_type];
  410.         ogl_cache_vclipn_textures(Vclip, w.flash_vclip);
  411.         ogl_cache_vclipn_textures(Vclip, w.robot_hit_vclip);
  412.         ogl_cache_vclipn_textures(Vclip, w.wall_hit_vclip);
  413.         if (w.render_type == WEAPON_RENDER_VCLIP)
  414.                 ogl_cache_vclipn_textures(Vclip, w.weapon_vclip);
  415.         else if (w.render_type == WEAPON_RENDER_POLYMODEL)
  416.         {
  417.                 ogl_cache_polymodel_textures(w.model_num);
  418.                 ogl_cache_polymodel_textures(w.model_num_inner);
  419.         }
  420. }
  421.  
  422. namespace dsx {
  423.  
  424. void ogl_cache_level_textures(void)
  425. {
  426.         auto &Effects = LevelUniqueEffectsClipState.Effects;
  427.         auto &Objects = LevelUniqueObjectState.Objects;
  428.         auto &vcobjptridx = Objects.vcptridx;
  429.         int max_efx=0,ef;
  430.        
  431.         ogl_reset_texture_stats_internal();//loading a new lev should reset textures
  432.        
  433.         range_for (auto &ec, partial_const_range(Effects, Num_effects))
  434.         {
  435.                 ogl_cache_vclipn_textures(Vclip, ec.dest_vclip);
  436.                 if ((ec.changing_wall_texture == -1) && (ec.changing_object_texture==-1) )
  437.                         continue;
  438.                 if (ec.vc.num_frames>max_efx)
  439.                         max_efx=ec.vc.num_frames;
  440.         }
  441.         glmprintf((CON_DEBUG, "max_efx:%i", max_efx));
  442.         for (ef=0;ef<max_efx;ef++){
  443.                 range_for (eclip &ec, partial_range(Effects, Num_effects))
  444.                 {
  445.                         if ((ec.changing_wall_texture == -1) && (ec.changing_object_texture==-1) )
  446.                                 continue;
  447.                         ec.time_left=-1;
  448.                 }
  449.                 do_special_effects();
  450.  
  451.                 range_for (const unique_segment &seg, vcsegptr)
  452.                 {
  453.                         range_for (auto &side, seg.sides)
  454.                         {
  455.                                 const auto tmap1 = side.tmap_num;
  456.                                 const auto tmap2 = side.tmap_num2;
  457.                                 if (tmap1<0 || tmap1>=NumTextures){
  458.                                         glmprintf((CON_DEBUG, "ogl_cache_level_textures %p %p %i %i", seg.get_unchecked_pointer(), &side, tmap1, NumTextures));
  459.                                         //                              tmap1=0;
  460.                                         continue;
  461.                                 }
  462.                                 PIGGY_PAGE_IN(Textures[tmap1]);
  463.                                 grs_bitmap *bm = &GameBitmaps[Textures[tmap1].index];
  464.                                 if (tmap2 != 0){
  465.                                         PIGGY_PAGE_IN(Textures[tmap2&0x3FFF]);
  466.                                         auto &bm2 = GameBitmaps[Textures[tmap2&0x3FFF].index];
  467.                                         if (CGameArg.DbgUseOldTextureMerge || bm2.get_flag_mask(BM_FLAG_SUPER_TRANSPARENT))
  468.                                                 bm = &texmerge_get_cached_bitmap( tmap1, tmap2 );
  469.                                         else {
  470.                                                 ogl_loadbmtexture(bm2, 1);
  471.                                         }
  472.                                 }
  473.                                 ogl_loadbmtexture(*bm, 0);
  474.                         }
  475.                 }
  476.                 glmprintf((CON_DEBUG, "finished ef:%i", ef));
  477.         }
  478.         reset_special_effects();
  479.         init_special_effects();
  480.         {
  481.                 auto &Robot_info = LevelSharedRobotInfoState.Robot_info;
  482.                 // always have lasers, concs, flares.  Always shows player appearance, and at least concs are always available to disappear.
  483.                 ogl_cache_weapon_textures(Vclip, Weapon_info, Primary_weapon_to_weapon_info[primary_weapon_index_t::LASER_INDEX]);
  484.                 ogl_cache_weapon_textures(Vclip, Weapon_info, Secondary_weapon_to_weapon_info[CONCUSSION_INDEX]);
  485.                 ogl_cache_weapon_textures(Vclip, Weapon_info, weapon_id_type::FLARE_ID);
  486.                 ogl_cache_vclipn_textures(Vclip, VCLIP_PLAYER_APPEARANCE);
  487.                 ogl_cache_vclipn_textures(Vclip, VCLIP_POWERUP_DISAPPEARANCE);
  488.                 ogl_cache_polymodel_textures(Player_ship->model_num);
  489.                 ogl_cache_vclipn_textures(Vclip, Player_ship->expl_vclip_num);
  490.  
  491.                 range_for (const auto &&objp, vcobjptridx)
  492.                 {
  493.                         if (objp->type == OBJ_POWERUP && objp->render_type==RT_POWERUP)
  494.                         {
  495.                                 ogl_cache_vclipn_textures(Vclip, objp->rtype.vclip_info.vclip_num);
  496.                                 const auto id = get_powerup_id(objp);
  497.                                 primary_weapon_index_t p;
  498.                                 secondary_weapon_index_t s;
  499.                                 int w;
  500.                                 if (
  501.                                         (
  502.                                                 (
  503.                                                         (id == POW_VULCAN_WEAPON && (p = primary_weapon_index_t::VULCAN_INDEX, true)) ||
  504.                                                         (id == POW_SPREADFIRE_WEAPON && (p = primary_weapon_index_t::SPREADFIRE_INDEX, true)) ||
  505.                                                         (id == POW_PLASMA_WEAPON && (p = primary_weapon_index_t::PLASMA_INDEX, true)) ||
  506.                                                         (id == POW_FUSION_WEAPON && (p = primary_weapon_index_t::FUSION_INDEX, true))
  507.                                                 ) && (w = Primary_weapon_to_weapon_info[p], true)
  508.                                         ) ||
  509.                                         (
  510.                                                 (
  511.                                                         (id == POW_PROXIMITY_WEAPON && (s = secondary_weapon_index_t::PROXIMITY_INDEX, true)) ||
  512.                                                         ((id == POW_HOMING_AMMO_1 || id == POW_HOMING_AMMO_4) && (s = secondary_weapon_index_t::HOMING_INDEX, true)) ||
  513.                                                         (id == POW_SMARTBOMB_WEAPON && (s = secondary_weapon_index_t::SMART_INDEX, true)) ||
  514.                                                         (id == POW_MEGA_WEAPON && (s = secondary_weapon_index_t::MEGA_INDEX, true))
  515.                                                 ) && (w = Secondary_weapon_to_weapon_info[s], true)
  516.                                         )
  517.                                 )
  518.                                 {
  519.                                         ogl_cache_weapon_textures(Vclip, Weapon_info, w);
  520.                                 }
  521.                         }
  522.                         else if (objp->type != OBJ_NONE && objp->render_type==RT_POLYOBJ)
  523.                         {
  524.                                 if (objp->type == OBJ_ROBOT)
  525.                                 {
  526.                                         auto &ri = Robot_info[get_robot_id(objp)];
  527.                                         ogl_cache_vclipn_textures(Vclip, ri.exp1_vclip_num);
  528.                                         ogl_cache_vclipn_textures(Vclip, ri.exp2_vclip_num);
  529.                                         ogl_cache_weapon_textures(Vclip, Weapon_info, ri.weapon_type);
  530.                                 }
  531.                                 if (objp->rtype.pobj_info.tmap_override != -1)
  532.                                 {
  533.                                         auto &t = Textures[objp->rtype.pobj_info.tmap_override];
  534.                                         PIGGY_PAGE_IN(t);
  535.                                         ogl_loadbmtexture(GameBitmaps[t.index], 1);
  536.                                 }
  537.                                 else
  538.                                         ogl_cache_polymodel_textures(objp->rtype.pobj_info.model_num);
  539.                         }
  540.                 }
  541.         }
  542.         glmprintf((CON_DEBUG, "finished caching"));
  543.         r_cachedtexcount = r_texcount;
  544. }
  545.  
  546. }
  547.  
  548. namespace dcx {
  549.  
  550. void g3_draw_line(grs_canvas &canvas, const g3s_point &p0, const g3s_point &p1, const uint8_t c)
  551. {
  552.         GLfloat color_r, color_g, color_b;
  553.         GLfloat color_array[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
  554.  
  555.         ogl_client_states<int, GL_VERTEX_ARRAY, GL_COLOR_ARRAY> cs;
  556.         OGL_DISABLE(TEXTURE_2D);
  557.         glDisable(GL_CULL_FACE);
  558.         color_r = PAL2Tr(c);
  559.         color_g = PAL2Tg(c);
  560.         color_b = PAL2Tb(c);
  561.         color_array[0] = color_array[4] = color_r;
  562.         color_array[1] = color_array[5] = color_g;
  563.         color_array[2] = color_array[6] = color_b;
  564.         color_array[3] = color_array[7] = 1.0;
  565.         std::array<GLfloat, 6> vertices = {{
  566.                 f2glf(p0.p3_vec.x), f2glf(p0.p3_vec.y), -f2glf(p0.p3_vec.z),
  567.                 f2glf(p1.p3_vec.x), f2glf(p1.p3_vec.y), -f2glf(p1.p3_vec.z)
  568.         }};
  569.         glVertexPointer(3, GL_FLOAT, 0, vertices.data());
  570.         glColorPointer(4, GL_FLOAT, 0, color_array);
  571.         glDrawArrays(GL_LINES, 0, 2);
  572. }
  573.  
  574. static void ogl_drawcircle(const unsigned nsides, const unsigned type, GLfloat *const vertices)
  575. {
  576.         glEnableClientState(GL_VERTEX_ARRAY);
  577.         glVertexPointer(2, GL_FLOAT, 0, vertices);
  578.         glDrawArrays(type, 0, nsides);
  579.         glDisableClientState(GL_VERTEX_ARRAY);
  580. }
  581.  
  582. static std::unique_ptr<GLfloat[]> circle_array_init(const unsigned nsides)
  583. {
  584.         auto vertices = std::make_unique<GLfloat[]>(nsides * 2);
  585.         for (unsigned i = 0; i < nsides; i++)
  586.         {
  587.                 const float ang = 2.0 * M_PI * i / nsides;
  588.                 vertices[i * 2] = cosf(ang);
  589.                 vertices[i * 2 + 1] = sinf(ang);
  590.         }
  591.         return vertices;
  592. }
  593.  
  594. static std::unique_ptr<GLfloat[]> circle_array_init_2(const unsigned nsides, const float xsc, const float xo, const float ysc, const float yo)
  595. {
  596.         auto vertices = std::make_unique<GLfloat[]>(nsides * 2);
  597.         for (unsigned i = 0; i < nsides; i++)
  598.         {
  599.                 const float ang = 2.0 * M_PI * i / nsides;
  600.                 vertices[i * 2] = cosf(ang) * xsc + xo;
  601.                 vertices[i * 2 + 1] = sinf(ang) * ysc + yo;
  602.         }
  603.         return vertices;
  604. }
  605.  
  606. }
  607.  
  608. void ogl_draw_vertex_reticle(int cross,int primary,int secondary,int color,int alpha,int size_offs)
  609. {
  610.         int size=270+(size_offs*20);
  611.         float scale = (static_cast<float>(SWIDTH)/SHEIGHT);
  612.         const std::array<float, 4> ret_rgba{{
  613.                 static_cast<float>(PAL2Tr(color)),
  614.                 static_cast<float>(PAL2Tg(color)),
  615.                 static_cast<float>(PAL2Tb(color)),
  616.                 static_cast<float>(1.0 - (static_cast<float>(alpha) / (static_cast<float>(GR_FADE_LEVELS))))
  617.         }}, ret_dark_rgba{{
  618.                 ret_rgba[0] / 2,
  619.                 ret_rgba[1] / 2,
  620.                 ret_rgba[2] / 2,
  621.                 ret_rgba[3] / 2
  622.         }};
  623.         std::array<GLfloat, 16 * 4> dark_lca, bright_lca;
  624.         for (uint_fast32_t i = 0; i != dark_lca.size(); i += 4)
  625.         {
  626.                 bright_lca[i] = ret_rgba[0];
  627.                 dark_lca[i] = ret_dark_rgba[0];
  628.                 bright_lca[i+1] = ret_rgba[1];
  629.                 dark_lca[i+1] = ret_dark_rgba[1];
  630.                 bright_lca[i+2] = ret_rgba[2];
  631.                 dark_lca[i+2] = ret_dark_rgba[2];
  632.                 bright_lca[i+3] = ret_rgba[3];
  633.                 dark_lca[i+3] = ret_dark_rgba[3];
  634.         }
  635.  
  636.         glPushMatrix();
  637.         glTranslatef((grd_curcanv->cv_bitmap.bm_w/2+grd_curcanv->cv_bitmap.bm_x)/static_cast<float>(last_width),1.0-(grd_curcanv->cv_bitmap.bm_h/2+grd_curcanv->cv_bitmap.bm_y)/static_cast<float>(last_height),0);
  638.  
  639.         {
  640.                 float gl1, gl2, gl3;
  641.         if (scale >= 1)
  642.         {
  643.                 size/=scale;
  644.                 gl2 = f2glf(size*scale);
  645.                 gl1 = f2glf(size);
  646.                 gl3 = gl1;
  647.         }
  648.         else
  649.         {
  650.                 size*=scale;
  651.                 gl1 = f2glf(size/scale);
  652.                 gl2 = f2glf(size);
  653.                 gl3 = gl2;
  654.         }
  655.                 glScalef(gl1, gl2, gl3);
  656.         }
  657.  
  658.         glLineWidth(linedotscale*2);
  659.         OGL_DISABLE(TEXTURE_2D);
  660.         glDisable(GL_CULL_FACE);
  661.         glEnableClientState(GL_VERTEX_ARRAY);
  662.         glEnableClientState(GL_COLOR_ARRAY);
  663.        
  664.         //cross
  665.         std::array<GLfloat, 8 * 4> cross_lca;
  666.         GLfloat *cross_lca_ptr;
  667.         if (cross)
  668.         {
  669.                 for (uint_fast32_t i = 0; i != cross_lca.size(); i += 8)
  670.                 {
  671.                         cross_lca[i] = ret_dark_rgba[0];
  672.                         cross_lca[i+1] = ret_dark_rgba[1];
  673.                         cross_lca[i+2] = ret_dark_rgba[2];
  674.                         cross_lca[i+3] = ret_dark_rgba[3];
  675.                         cross_lca[i+4] = ret_rgba[0];
  676.                         cross_lca[i+5] = ret_rgba[1];
  677.                         cross_lca[i+6] = ret_rgba[2];
  678.                         cross_lca[i+7] = ret_rgba[3];
  679.                 }
  680.                 cross_lca_ptr = cross_lca.data();
  681.         }
  682.         else
  683.         {
  684.                 cross_lca_ptr = dark_lca.data();
  685.         }
  686.         glColorPointer(4, GL_FLOAT, 0, cross_lca_ptr);
  687.  
  688.         static const std::array<GLfloat, 8 * 2> cross_lva{{
  689.                 -4.0, 2.0, -2.0, 0, -3.0, -4.0, -2.0, -3.0, 4.0, 2.0, 2.0, 0, 3.0, -4.0, 2.0, -3.0,
  690.         }};
  691.         glVertexPointer(2, GL_FLOAT, 0, cross_lva.data());
  692.         glDrawArrays(GL_LINES, 0, 8);
  693.        
  694.         std::array<GLfloat, 4 * 4> primary_lca0;
  695.         GLfloat *lca0_data;
  696.         //left primary bar
  697.         if(primary == 0)
  698.                 lca0_data = dark_lca.data();
  699.         else
  700.         {
  701.                 primary_lca0[0] = primary_lca0[4] = ret_rgba[0];
  702.                 primary_lca0[1] = primary_lca0[5] = ret_rgba[1];
  703.                 primary_lca0[2] = primary_lca0[6] = ret_rgba[2];
  704.                 primary_lca0[3] = primary_lca0[7] = ret_rgba[3];
  705.                 primary_lca0[8] = primary_lca0[12] = ret_dark_rgba[0];
  706.                 primary_lca0[9] = primary_lca0[13] = ret_dark_rgba[1];
  707.                 primary_lca0[10] = primary_lca0[14] = ret_dark_rgba[2];
  708.                 primary_lca0[11] = primary_lca0[15] = ret_dark_rgba[3];
  709.                 lca0_data = primary_lca0.data();
  710.         }
  711.         glColorPointer(4, GL_FLOAT, 0, lca0_data);
  712.         static const std::array<GLfloat, 4 * 2> primary_lva0{{
  713.                 -5.5, -5.0, -6.5, -7.5, -10.0, -7.0, -10.0, -8.7
  714.         }};
  715.         static const std::array<GLfloat, 4 * 2> primary_lva1{{
  716.                 -10.0, -7.0, -10.0, -8.7, -15.0, -8.5, -15.0, -9.5
  717.         }};
  718.         static const std::array<GLfloat, 4 * 2> primary_lva2{{
  719.                 5.5, -5.0, 6.5, -7.5, 10.0, -7.0, 10.0, -8.7
  720.         }};
  721.         static const std::array<GLfloat, 4 * 2> primary_lva3{{
  722.                 10.0, -7.0, 10.0, -8.7, 15.0, -8.5, 15.0, -9.5
  723.         }};
  724.         glVertexPointer(2, GL_FLOAT, 0, primary_lva0.data());
  725.         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  726.  
  727.         std::array<GLfloat, 4 * 4> primary_lca1;
  728.         GLfloat *lca1_data;
  729.         if(primary != 2)
  730.                 lca1_data = dark_lca.data();
  731.         else
  732.         {
  733.                 primary_lca1[8] = primary_lca1[12] = ret_rgba[0];
  734.                 primary_lca1[9] = primary_lca1[13] = ret_rgba[1];
  735.                 primary_lca1[10] = primary_lca1[14] = ret_rgba[2];
  736.                 primary_lca1[11] = primary_lca1[15] = ret_rgba[3];
  737.                 primary_lca1[0] = primary_lca1[4] = ret_dark_rgba[0];
  738.                 primary_lca1[1] = primary_lca1[5] = ret_dark_rgba[1];
  739.                 primary_lca1[2] = primary_lca1[6] = ret_dark_rgba[2];
  740.                 primary_lca1[3] = primary_lca1[7] = ret_dark_rgba[3];
  741.                 lca1_data = primary_lca1.data();
  742.         }
  743.         glColorPointer(4, GL_FLOAT, 0, lca1_data);
  744.         glVertexPointer(2, GL_FLOAT, 0, primary_lva1.data());
  745.         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  746.         //right primary bar
  747.         glColorPointer(4, GL_FLOAT, 0, lca0_data);
  748.         glVertexPointer(2, GL_FLOAT, 0, primary_lva2.data());
  749.         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  750.         glColorPointer(4, GL_FLOAT, 0, lca1_data);
  751.         glVertexPointer(2, GL_FLOAT, 0, primary_lva3.data());
  752.         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  753.        
  754.         GLfloat *secondary_lva_ptr;
  755.         if (secondary<=2){
  756.                 //left secondary
  757.                 glColorPointer(4, GL_FLOAT, 0, (secondary != 1 ? dark_lca : bright_lca).data());
  758.                 if(!secondary_lva[0])
  759.                         secondary_lva[0] = circle_array_init_2(16, 2.0, -10.0, 2.0, -2.0);
  760.                 ogl_drawcircle(16, GL_LINE_LOOP, secondary_lva[0].get());
  761.                 //right secondary
  762.                 glColorPointer(4, GL_FLOAT, 0, (secondary != 2 ? dark_lca : bright_lca).data());
  763.                 if(!secondary_lva[1])
  764.                         secondary_lva[1] = circle_array_init_2(16, 2.0, 10.0, 2.0, -2.0);
  765.                 secondary_lva_ptr = secondary_lva[1].get();
  766.         }
  767.         else {
  768.                 //bottom/middle secondary
  769.                 glColorPointer(4, GL_FLOAT, 0, (secondary != 4 ? dark_lca : bright_lca).data());
  770.                 if(!secondary_lva[2])
  771.                         secondary_lva[2] = circle_array_init_2(16, 2.0, 0.0, 2.0, -8.0);
  772.                 secondary_lva_ptr = secondary_lva[2].get();
  773.         }
  774.         ogl_drawcircle(16, GL_LINE_LOOP, secondary_lva_ptr);
  775.        
  776.         //glDisableClientState(GL_VERTEX_ARRAY);
  777.         glDisableClientState(GL_COLOR_ARRAY);
  778.         glPopMatrix();
  779.         glLineWidth(linedotscale);
  780. }
  781.  
  782. namespace dcx {
  783.  
  784. /*
  785.  * Stars on heaven in exit sequence, automap objects
  786.  */
  787. void g3_draw_sphere(grs_canvas &canvas, cg3s_point &pnt, fix rad, const uint8_t c)
  788. {
  789.         int i;
  790.         const float scale = (static_cast<float>(canvas.cv_bitmap.bm_w) / canvas.cv_bitmap.bm_h);
  791.         std::array<GLfloat, 20 * 4> color_array;
  792.         for (i = 0; i < 20*4; i += 4)
  793.         {
  794.                 color_array[i] = CPAL2Tr(c);
  795.                 color_array[i+1] = CPAL2Tg(c);
  796.                 color_array[i+2] = CPAL2Tb(c);
  797.                 color_array[i+3] = 1.0;
  798.         }
  799.         OGL_DISABLE(TEXTURE_2D);
  800.         glDisable(GL_CULL_FACE);
  801.         glPushMatrix();
  802.         glTranslatef(f2glf(pnt.p3_vec.x),f2glf(pnt.p3_vec.y),-f2glf(pnt.p3_vec.z));
  803.         GLfloat gl1, gl2;
  804.         if (scale >= 1)
  805.         {
  806.                 rad/=scale;
  807.                 gl1 = f2glf(rad);
  808.                 gl2 = f2glf(rad*scale);
  809.         }
  810.         else
  811.         {
  812.                 rad*=scale;
  813.                 gl1 = f2glf(rad/scale);
  814.                 gl2 = f2glf(rad);
  815.         }
  816.         glScalef(gl1, gl2, f2glf(rad));
  817.         if(!sphere_va)
  818.                 sphere_va = circle_array_init(20);
  819.         glEnableClientState(GL_COLOR_ARRAY);
  820.         glColorPointer(4, GL_FLOAT, 0, color_array.data());
  821.         ogl_drawcircle(20, GL_TRIANGLE_FAN, sphere_va.get());
  822.         glDisableClientState(GL_COLOR_ARRAY);
  823.         glPopMatrix();
  824. }
  825.  
  826. int gr_ucircle(grs_canvas &canvas, const fix xc1, const fix yc1, const fix r1, const uint8_t c)
  827. {
  828.         int nsides;
  829.         OGL_DISABLE(TEXTURE_2D);
  830.         glColor4f(CPAL2Tr(c), CPAL2Tg(c), CPAL2Tb(c), (canvas.cv_fade_level >= GR_FADE_OFF)?1.0:1.0 - static_cast<float>(canvas.cv_fade_level) / (static_cast<float>(GR_FADE_LEVELS) - 1.0));
  831.         glPushMatrix();
  832.         glTranslatef(
  833.                      (f2fl(xc1) + canvas.cv_bitmap.bm_x + 0.5) / static_cast<float>(last_width),
  834.                      1.0 - (f2fl(yc1) + canvas.cv_bitmap.bm_y + 0.5) / static_cast<float>(last_height),0);
  835.         glScalef(f2fl(r1) / last_width, f2fl(r1) / last_height, 1.0);
  836.         nsides = 10 + 2 * static_cast<int>(M_PI * f2fl(r1) / 19);
  837.         if(!circle_va)
  838.                 circle_va = circle_array_init(nsides);
  839.         ogl_drawcircle(nsides, GL_LINE_LOOP, circle_va.get());
  840.         glPopMatrix();
  841.         return 0;
  842. }
  843.  
  844. int gr_disk(grs_canvas &canvas, const fix x, const fix y, const fix r, const uint8_t c)
  845. {
  846.         int nsides;
  847.         OGL_DISABLE(TEXTURE_2D);
  848.         glColor4f(CPAL2Tr(c), CPAL2Tg(c), CPAL2Tb(c), (canvas.cv_fade_level >= GR_FADE_OFF) ? 1.0 : 1.0 - static_cast<float>(canvas.cv_fade_level) / (static_cast<float>(GR_FADE_LEVELS) - 1.0));
  849.         glPushMatrix();
  850.         glTranslatef(
  851.                      (f2fl(x) + canvas.cv_bitmap.bm_x + 0.5) / static_cast<float>(last_width),
  852.                      1.0 - (f2fl(y) + canvas.cv_bitmap.bm_y + 0.5) / static_cast<float>(last_height),0);
  853.         glScalef(f2fl(r) / last_width, f2fl(r) / last_height, 1.0);
  854.         nsides = 10 + 2 * static_cast<int>(M_PI * f2fl(r) / 19);
  855.         if(!disk_va)
  856.                 disk_va = circle_array_init(nsides);
  857.         ogl_drawcircle(nsides, GL_TRIANGLE_FAN, disk_va.get());
  858.         glPopMatrix();
  859.         return 0;
  860. }
  861.  
  862. /*
  863.  * Draw flat-shaded Polygon (Lasers, Drone-arms, Driller-ears)
  864.  */
  865. void _g3_draw_poly(grs_canvas &canvas, const uint_fast32_t nv, cg3s_point *const *const pointlist, const uint8_t palette_color_index)
  866. {
  867.         if (nv > MAX_POINTS_PER_POLY)
  868.                 return;
  869.         flatten_array<GLfloat, 4, MAX_POINTS_PER_POLY> color_array;
  870.         flatten_array<GLfloat, 3, MAX_POINTS_PER_POLY> vertices;
  871.  
  872.         r_polyc++;
  873.         ogl_client_states<int, GL_VERTEX_ARRAY, GL_COLOR_ARRAY> cs;
  874.         OGL_DISABLE(TEXTURE_2D);
  875.         const float color_r = PAL2Tr(palette_color_index), color_g = PAL2Tg(palette_color_index), color_b = PAL2Tb(palette_color_index);
  876.  
  877.         const float color_a = (canvas.cv_fade_level >= GR_FADE_OFF)
  878.                 ? 1.0
  879.                 : 1.0 - static_cast<float>(canvas.cv_fade_level) / (static_cast<float>(GR_FADE_LEVELS) - 1.0);
  880.  
  881.         for (auto &&[p, v, c] : zip(
  882.                         unchecked_partial_range(pointlist, nv),
  883.                         unchecked_partial_range(vertices.nested.data(), nv),
  884.                         unchecked_partial_range(color_array.nested.data(), nv)
  885.                 )
  886.         )
  887.         {
  888.                 c[0] = color_r;
  889.                 c[1] = color_g;
  890.                 c[2] = color_b;
  891.                 c[3] = color_a;
  892.                 auto &pv = p->p3_vec;
  893.                 v[0] = f2glf(pv.x);
  894.                 v[1] = f2glf(pv.y);
  895.                 v[2] = -f2glf(pv.z);
  896.         }
  897.  
  898.         glVertexPointer(3, GL_FLOAT, 0, vertices.flat.data());
  899.         glColorPointer(4, GL_FLOAT, 0, color_array.flat.data());
  900.         glDrawArrays(GL_TRIANGLE_FAN, 0, nv);
  901. }
  902.  
  903. /*
  904.  * Everything texturemapped (walls, robots, ship)
  905.  */
  906. void _g3_draw_tmap(grs_canvas &canvas, const unsigned nv, cg3s_point *const *const pointlist, const g3s_uvl *const uvl_list, const g3s_lrgb *const light_rgb, grs_bitmap &bm)
  907. {
  908.         GLfloat color_alpha = 1.0;
  909.  
  910.         ogl_client_states<int, GL_VERTEX_ARRAY, GL_COLOR_ARRAY> cs;
  911.         if (tmap_drawer_ptr == draw_tmap) {
  912.                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  913.                 OGL_ENABLE(TEXTURE_2D);
  914.                 ogl_bindbmtex(bm, 0);
  915.                 ogl_texwrap(bm.gltexture, GL_REPEAT);
  916.                 r_tpolyc++;
  917.                 color_alpha = (canvas.cv_fade_level >= GR_FADE_OFF) ? 1.0 : (1.0 - static_cast<float>(canvas.cv_fade_level) / (static_cast<float>(GR_FADE_LEVELS) - 1.0));
  918.         } else if (tmap_drawer_ptr == draw_tmap_flat) {
  919.                 OGL_DISABLE(TEXTURE_2D);
  920.                 /* for cloaked state faces */
  921.                 color_alpha = 1.0 - (canvas.cv_fade_level / static_cast<GLfloat>(NUM_LIGHTING_LEVELS));
  922.         } else {
  923.                 glmprintf((CON_DEBUG, "g3_draw_tmap: unhandled tmap_drawer"));
  924.                 return;
  925.         }
  926.  
  927.         flatten_array<GLfloat, 3, MAX_POINTS_PER_POLY> vertices;
  928.         flatten_array<GLfloat, 4, MAX_POINTS_PER_POLY> color_array;
  929.         flatten_array<GLfloat, 2, MAX_POINTS_PER_POLY> texcoord_array;
  930.  
  931.         for (auto &&[point, light, uvl, vert, color, texcoord] : zip(
  932.                         unchecked_partial_range(pointlist, nv),
  933.                         unchecked_partial_range(light_rgb, nv),
  934.                         unchecked_partial_range(uvl_list, nv),
  935.                         unchecked_partial_range(vertices.nested.data(), nv),
  936.                         unchecked_partial_range(color_array.nested.data(), nv),
  937.                         partial_range(texcoord_array.nested, nv)
  938.                 )
  939.         )
  940.         {
  941.                 vert[0] = f2glf(point->p3_vec.x);
  942.                 vert[1] = f2glf(point->p3_vec.y);
  943.                 vert[2] = -f2glf(point->p3_vec.z);
  944.                 color[3] = color_alpha;
  945.                 if (tmap_drawer_ptr == draw_tmap_flat) {
  946.                         color[0] = color[1] = color[2] = 0;
  947.                 }
  948.                 else
  949.                 {
  950.                         if (bm.get_flag_mask(BM_FLAG_NO_LIGHTING))
  951.                         {
  952.                                 color[0] = color[1] = color[2] = 1.0;
  953.                         }
  954.                         else
  955.                         {
  956.                                 color[0] = f2glf(light.r);
  957.                                 color[1] = f2glf(light.g);
  958.                                 color[2] = f2glf(light.b);
  959.                         }
  960.                         texcoord[0] = f2glf(uvl.u);
  961.                         texcoord[1] = f2glf(uvl.v);
  962.                 }
  963.         }
  964.  
  965.         glVertexPointer(3, GL_FLOAT, 0, vertices.flat.data());
  966.         glColorPointer(4, GL_FLOAT, 0, color_array.flat.data());
  967.         if (tmap_drawer_ptr == draw_tmap) {
  968.                 glTexCoordPointer(2, GL_FLOAT, 0, texcoord_array.flat.data());
  969.         }
  970.        
  971.         glDrawArrays(GL_TRIANGLE_FAN, 0, nv);
  972.        
  973.         glDisableClientState(GL_VERTEX_ARRAY);
  974.         glDisableClientState(GL_COLOR_ARRAY);
  975.         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  976. }
  977.  
  978. }
  979.  
  980. /*
  981.  * Everything texturemapped with secondary texture (walls with secondary texture)
  982.  */
  983. void _g3_draw_tmap_2(grs_canvas &canvas, const unsigned nv, const g3s_point *const *const pointlist, const g3s_uvl *uvl_list, const g3s_lrgb *light_rgb, grs_bitmap &bmbot, grs_bitmap &bm, const unsigned orient)
  984. {
  985.         _g3_draw_tmap(canvas, nv, pointlist, uvl_list, light_rgb, bmbot);//draw the bottom texture first.. could be optimized with multitexturing..
  986.         ogl_client_states<int, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY> cs;
  987.         (void)cs;
  988.         r_tpolyc++;
  989.         OGL_ENABLE(TEXTURE_2D);
  990.         ogl_bindbmtex(bm, 1);
  991.         ogl_texwrap(bm.gltexture, GL_REPEAT);
  992.  
  993.         flatten_array<GLfloat, 4, MAX_POINTS_PER_POLY> color_array;
  994.         {
  995.                 const GLfloat alpha = (canvas.cv_fade_level >= GR_FADE_OFF)
  996.                         ? 1.0
  997.                         : (1.0 - static_cast<float>(canvas.cv_fade_level) / (static_cast<float>(GR_FADE_LEVELS) - 1.0));
  998.                 auto &&color_range = unchecked_partial_range(color_array.nested.data(), nv);
  999.                 if (bm.get_flag_mask(BM_FLAG_NO_LIGHTING))
  1000.                 {
  1001.                         for (auto &e : color_range)
  1002.                         {
  1003.                                 e[0] = e[1] = e[2] = 1.0;
  1004.                                 e[3] = alpha;
  1005.                         }
  1006.                 }
  1007.                 else
  1008.                 {
  1009.                         for (auto &&[e, l] : zip(
  1010.                                         color_range,
  1011.                                         unchecked_partial_range(light_rgb, nv)
  1012.                                 )
  1013.                         )
  1014.                         {
  1015.                                 e[0] = f2glf(l.r);
  1016.                                 e[1] = f2glf(l.g);
  1017.                                 e[2] = f2glf(l.b);
  1018.                                 e[3] = alpha;
  1019.                         }
  1020.                 }
  1021.         }
  1022.  
  1023.         flatten_array<GLfloat, 3, MAX_POINTS_PER_POLY> vertices;
  1024.         flatten_array<GLfloat, 2, MAX_POINTS_PER_POLY> texcoord_array;
  1025.  
  1026.         for (auto &&[point, uvl, vert, texcoord] : zip(
  1027.                         unchecked_partial_range(pointlist, nv),
  1028.                         unchecked_partial_range(uvl_list, nv),
  1029.                         unchecked_partial_range(vertices.nested.data(), nv),
  1030.                         partial_range(texcoord_array.nested, nv)
  1031.                 )
  1032.         )
  1033.         {
  1034.                 const GLfloat uf = f2glf(uvl.u), vf = f2glf(uvl.v);
  1035.                 switch(orient){
  1036.                         case 1:
  1037.                                 texcoord[0] = 1.0 - vf;
  1038.                                 texcoord[1] = uf;
  1039.                                 break;
  1040.                         case 2:
  1041.                                 texcoord[0] = 1.0 - uf;
  1042.                                 texcoord[1] = 1.0 - vf;
  1043.                                 break;
  1044.                         case 3:
  1045.                                 texcoord[0] = vf;
  1046.                                 texcoord[1] = 1.0 - uf;
  1047.                                 break;
  1048.                         default:
  1049.                                 texcoord[0] = uf;
  1050.                                 texcoord[1] = vf;
  1051.                                 break;
  1052.                 }
  1053.                 vert[0] = f2glf(point->p3_vec.x);
  1054.                 vert[1] = f2glf(point->p3_vec.y);
  1055.                 vert[2] = -f2glf(point->p3_vec.z);
  1056.         }
  1057.         glVertexPointer(3, GL_FLOAT, 0, vertices.flat.data());
  1058.         glColorPointer(4, GL_FLOAT, 0, color_array.flat.data());
  1059.         glTexCoordPointer(2, GL_FLOAT, 0, texcoord_array.flat.data());
  1060.         glDrawArrays(GL_TRIANGLE_FAN, 0, nv);
  1061. }
  1062.  
  1063. namespace dcx {
  1064.  
  1065. /*
  1066.  * 2d Sprites (Fireaballs, powerups, explosions). NOT hostages
  1067.  */
  1068. void g3_draw_bitmap(grs_canvas &canvas, const vms_vector &pos, const fix iwidth, const fix iheight, grs_bitmap &bm)
  1069. {
  1070.         r_bitmapc++;
  1071.        
  1072.         ogl_client_states<int, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY> cs;
  1073.         auto &i = std::get<0>(cs);
  1074.  
  1075.         OGL_ENABLE(TEXTURE_2D);
  1076.         ogl_bindbmtex(bm, 0);
  1077.         ogl_texwrap(bm.gltexture,GL_CLAMP_TO_EDGE);
  1078.  
  1079.         const auto width = fixmul(iwidth, Matrix_scale.x);
  1080.         const auto height = fixmul(iheight, Matrix_scale.y);
  1081.         constexpr unsigned point_count = 4;
  1082.         struct fvertex_t
  1083.         {
  1084.                 GLfloat x, y, z;
  1085.         };
  1086.         struct fcolor_t
  1087.         {
  1088.                 GLfloat r, g, b, a;
  1089.         };
  1090.         struct ftexcoord_t
  1091.         {
  1092.                 GLfloat u, v;
  1093.         };
  1094.         std::array<fvertex_t, point_count> vertices;
  1095.         std::array<fcolor_t, point_count> color_array;
  1096.         std::array<ftexcoord_t, point_count> texcoord_array;
  1097.         const auto &v1 = vm_vec_sub(pos,View_position);
  1098.         const auto &rpv = vm_vec_rotate(v1,View_matrix);
  1099.         const auto bmglu = bm.gltexture->u;
  1100.         const auto bmglv = bm.gltexture->v;
  1101.         const auto alpha = canvas.cv_fade_level >= GR_FADE_OFF ? 1.0 : (1.0 - static_cast<float>(canvas.cv_fade_level) / (static_cast<float>(GR_FADE_LEVELS) - 1.0));
  1102.         const auto vert_z = -f2glf(rpv.z);
  1103.         for (i=0;i<4;i++){
  1104.                 auto pv = rpv;
  1105.                 switch (i){
  1106.                         case 0:
  1107.                                 texcoord_array[i].u = 0.0;
  1108.                                 texcoord_array[i].v = 0.0;
  1109.                                 pv.x+=-width;
  1110.                                 pv.y+=height;
  1111.                                 break;
  1112.                         case 1:
  1113.                                 texcoord_array[i].u = bmglu;
  1114.                                 texcoord_array[i].v = 0.0;
  1115.                                 pv.x+=width;
  1116.                                 pv.y+=height;
  1117.                                 break;
  1118.                         case 2:
  1119.                                 texcoord_array[i].u = bmglu;
  1120.                                 texcoord_array[i].v = bmglv;
  1121.                                 pv.x+=width;
  1122.                                 pv.y+=-height;
  1123.                                 break;
  1124.                         case 3:
  1125.                                 texcoord_array[i].u = 0.0;
  1126.                                 texcoord_array[i].v = bmglv;
  1127.                                 pv.x+=-width;
  1128.                                 pv.y+=-height;
  1129.                                 break;
  1130.                 }
  1131.  
  1132.                 color_array[i].r = 1.0;
  1133.                 color_array[i].g = 1.0;
  1134.                 color_array[i].b = 1.0;
  1135.                 color_array[i].a = alpha;
  1136.                 vertices[i].x = f2glf(pv.x);
  1137.                 vertices[i].y = f2glf(pv.y);
  1138.                 vertices[i].z = vert_z;
  1139.         }
  1140.         glVertexPointer(3, GL_FLOAT, 0, vertices.data());
  1141.         glColorPointer(4, GL_FLOAT, 0, color_array.data());
  1142.         glTexCoordPointer(2, GL_FLOAT, 0, texcoord_array.data());
  1143.         glDrawArrays(GL_TRIANGLE_FAN, 0, 4); // Replaced GL_QUADS
  1144. }
  1145.  
  1146. /*
  1147.  * Movies
  1148.  * Since this function will create a new texture each call, mipmapping can be very GPU intensive - so it has an optional setting for texture filtering.
  1149.  */
  1150. bool ogl_ubitblt_i(unsigned dw,unsigned dh,unsigned dx,unsigned dy, unsigned sw, unsigned sh, unsigned sx, unsigned sy, const grs_bitmap &src, grs_bitmap &dest, unsigned texfilt)
  1151. {
  1152.         GLfloat xo,yo,xs,ys,u1,v1;
  1153.         GLfloat color_array[] = { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
  1154.         GLfloat texcoord_array[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
  1155.         GLfloat vertices[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
  1156.         struct bitblt_free_ogl_texture
  1157.         {
  1158.                 ogl_texture t;
  1159.                 ~bitblt_free_ogl_texture()
  1160.                 {
  1161.                         ogl_freetexture(t);
  1162.                 }
  1163.         };
  1164.         ogl_client_states<bitblt_free_ogl_texture, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY> cs;
  1165.         ogl_texture &tex = std::get<0>(cs).t;
  1166.         r_ubitbltc++;
  1167.  
  1168.         ogl_init_texture(tex, sw, sh, OGL_FLAG_ALPHA);
  1169.         tex.prio = 0.0;
  1170.         tex.lw=src.bm_rowsize;
  1171.  
  1172.         u1=v1=0;
  1173.        
  1174.         dx+=dest.bm_x;
  1175.         dy+=dest.bm_y;
  1176.         xo=dx/static_cast<float>(last_width);
  1177.         xs=dw/static_cast<float>(last_width);
  1178.         yo=1.0-dy/static_cast<float>(last_height);
  1179.         ys=dh/static_cast<float>(last_height);
  1180.        
  1181.         OGL_ENABLE(TEXTURE_2D);
  1182.        
  1183.         ogl_loadtexture(gr_current_pal, src.get_bitmap_data(), sx, sy, tex, src.get_flags(), 0, texfilt, 0, 0);
  1184.         OGL_BINDTEXTURE(tex.handle);
  1185.        
  1186.         ogl_texwrap(&tex,GL_CLAMP_TO_EDGE);
  1187.  
  1188.         vertices[0] = xo;
  1189.         vertices[1] = yo;
  1190.         vertices[2] = xo+xs;
  1191.         vertices[3] = yo;
  1192.         vertices[4] = xo+xs;
  1193.         vertices[5] = yo-ys;
  1194.         vertices[6] = xo;
  1195.         vertices[7] = yo-ys;
  1196.  
  1197.         texcoord_array[0] = u1;
  1198.         texcoord_array[1] = v1;
  1199.         texcoord_array[2] = tex.u;
  1200.         texcoord_array[3] = v1;
  1201.         texcoord_array[4] = tex.u;
  1202.         texcoord_array[5] = tex.v;
  1203.         texcoord_array[6] = u1;
  1204.         texcoord_array[7] = tex.v;
  1205.  
  1206.         glVertexPointer(2, GL_FLOAT, 0, vertices);
  1207.         glColorPointer(4, GL_FLOAT, 0, color_array);
  1208.         glTexCoordPointer(2, GL_FLOAT, 0, texcoord_array);  
  1209.         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);//replaced GL_QUADS
  1210.         return 0;
  1211. }
  1212.  
  1213. bool ogl_ubitblt(unsigned w,unsigned h,unsigned dx,unsigned dy, unsigned sx, unsigned sy, const grs_bitmap &src, grs_bitmap &dest){
  1214.         return ogl_ubitblt_i(w,h,dx,dy,w,h,sx,sy,src,dest,0);
  1215. }
  1216.  
  1217. /*
  1218.  * set depth testing on or off
  1219.  */
  1220. void ogl_toggle_depth_test(int enable)
  1221. {
  1222.         if (enable)
  1223.                 glEnable(GL_DEPTH_TEST);
  1224.         else
  1225.                 glDisable(GL_DEPTH_TEST);
  1226. }
  1227.  
  1228. /*
  1229.  * set blending function
  1230.  */
  1231. void ogl_set_blending(const gr_blend cv_blend_func)
  1232. {
  1233.         GLenum s, d;
  1234.         switch (cv_blend_func)
  1235.         {
  1236.                 case gr_blend::additive_a:
  1237.                         s = GL_SRC_ALPHA;
  1238.                         d = GL_ONE;
  1239.                         break;
  1240.                 case gr_blend::additive_c:
  1241.                         s = GL_ONE;
  1242.                         d = GL_ONE;
  1243.                         break;
  1244.                 case gr_blend::normal:
  1245.                 default:
  1246.                         s = GL_SRC_ALPHA;
  1247.                         d = GL_ONE_MINUS_SRC_ALPHA;
  1248.                         break;
  1249.         }
  1250.         glBlendFunc(s, d);
  1251. }
  1252.  
  1253. void ogl_start_frame(grs_canvas &canvas)
  1254. {
  1255.         r_polyc=0;r_tpolyc=0;r_bitmapc=0;r_ubitbltc=0;
  1256.  
  1257.         OGL_VIEWPORT(canvas.cv_bitmap.bm_x, canvas.cv_bitmap.bm_y, canvas.cv_bitmap.bm_w, canvas.cv_bitmap.bm_h);
  1258.         glClearColor(0.0, 0.0, 0.0, 0.0);
  1259.  
  1260.         glLineWidth(linedotscale);
  1261.         glEnable(GL_BLEND);
  1262.         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  1263.  
  1264.         glEnable(GL_ALPHA_TEST);
  1265.         glAlphaFunc(GL_GEQUAL,0.02);
  1266.         glEnable(GL_DEPTH_TEST);
  1267.         glDepthFunc(GL_LEQUAL);
  1268.  
  1269.         glClear(GL_DEPTH_BUFFER_BIT);
  1270.         glEnable(GL_CULL_FACE);
  1271.         glCullFace(GL_FRONT);
  1272.  
  1273.         glShadeModel(GL_SMOOTH);
  1274.         glMatrixMode(GL_PROJECTION);
  1275.         glLoadIdentity();//clear matrix
  1276. #if DXX_USE_OGLES
  1277.         perspective(90.0,1.0,0.1,5000.0);  
  1278. #else
  1279.         gluPerspective(90.0,1.0,0.1,5000.0);
  1280. #endif
  1281.         glMatrixMode(GL_MODELVIEW);
  1282.         glLoadIdentity();//clear matrix
  1283. }
  1284.  
  1285. void ogl_end_frame(void){
  1286.         OGL_VIEWPORT(0, 0, grd_curscreen->get_screen_width(), grd_curscreen->get_screen_height());
  1287.         glMatrixMode(GL_PROJECTION);
  1288.         glLoadIdentity();//clear matrix
  1289. #if DXX_USE_OGLES
  1290.         glOrthof(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
  1291. #else
  1292.         glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
  1293. #endif
  1294.         glMatrixMode(GL_MODELVIEW);
  1295.         glLoadIdentity();//clear matrix
  1296.         glDisable(GL_CULL_FACE);
  1297.         glDisable(GL_DEPTH_TEST);
  1298. }
  1299.  
  1300. void gr_flip(void)
  1301. {
  1302.         if (CGameArg.DbgRenderStats)
  1303.                 ogl_texture_stats();
  1304.  
  1305.         ogl_do_palfx();
  1306.         ogl_swap_buffers_internal();
  1307.         glClear(GL_COLOR_BUFFER_BIT);
  1308. }
  1309.  
  1310. //little hack to find the nearest bigger power of 2 for a given number
  1311. unsigned pow2ize(unsigned f0){
  1312.         unsigned f1 = (f0 - 1) | 1;
  1313.         for (unsigned i = 4; i -- > 0;)
  1314.                 f1 |= f1 >> (1 << i);
  1315.         unsigned f2 = f1 + 1;
  1316.         assert(f2 >= f0);
  1317.         assert(!(f2 & f1));
  1318.         assert((f2 >> 1) < f0);
  1319.         return f2;
  1320. }
  1321.  
  1322. // Allocate the pixel buffers 'pixels' and 'texbuf' based on current screen resolution
  1323. void ogl_init_pixel_buffers(unsigned w, unsigned h)
  1324. {
  1325.         w = pow2ize(w); // convert to OpenGL texture size
  1326.         h = pow2ize(h);
  1327.  
  1328.         texbuf = std::make_unique<GLubyte[]>(max(w, 1024u)*max(h, 256u)*4);     // must also fit big font texture
  1329. }
  1330.  
  1331. void ogl_close_pixel_buffers(void)
  1332. {
  1333.         texbuf.reset();
  1334. }
  1335.  
  1336. static void ogl_filltexbuf(const palette_array_t &pal, const uint8_t *const data, GLubyte *texp, const unsigned truewidth, const unsigned width, const unsigned height, const int dxo, const int dyo, const unsigned twidth, const unsigned theight, const int type, const int bm_flags, const int data_format)
  1337. {
  1338.         if ((width > max(static_cast<unsigned>(grd_curscreen->get_screen_width()), 1024u)) ||
  1339.                 (height > max(static_cast<unsigned>(grd_curscreen->get_screen_height()), 256u)))
  1340.                 Error("Texture is too big: %ix%i", width, height);
  1341.  
  1342.         for (unsigned y=0;y<theight;y++)
  1343.         {
  1344.                 int i=dxo+truewidth*(y+dyo);
  1345.                 for (unsigned x=0;x<twidth;x++)
  1346.                 {
  1347.                         int c;
  1348.                         if (x<width && y<height)
  1349.                         {
  1350.                                 if (data_format)
  1351.                                 {
  1352.                                         int j;
  1353.  
  1354.                                         for (j = 0; j < data_format; ++j)
  1355.                                                 (*(texp++)) = data[i * data_format + j];
  1356.                                         i++;
  1357.                                         continue;
  1358.                                 }
  1359.                                 else
  1360.                                 {
  1361.                                         c = data[i++];
  1362.                                 }
  1363.                         }
  1364.                         else if (x == width && y < height) // end of bitmap reached - fill this pixel with last color to make a clean border when filtering this texture
  1365.                         {
  1366.                                 c = data[(width*(y+1))-1];
  1367.                         }
  1368.                         else if (y == height && x < width) // end of bitmap reached - fill this row with color or last row to make a clean border when filtering this texture
  1369.                         {
  1370.                                 c = data[(width*(height-1))+x];
  1371.                         }
  1372.                         else
  1373.                         {
  1374.                                 c = 256; // fill the pad space with transparency (or blackness)
  1375.                         }
  1376.  
  1377.                         if (c == 254 && (bm_flags & BM_FLAG_SUPER_TRANSPARENT))
  1378.                         {
  1379.                                 switch (type)
  1380.                                 {
  1381.                                         case GL_RGBA:
  1382.                                                 (*(texp++)) = 255;
  1383.                                                 (*(texp++)) = 255;
  1384.                                                 DXX_BOOST_FALLTHROUGH;
  1385.                                         case GL_LUMINANCE_ALPHA:
  1386.                                                 (*(texp++)) = 255;
  1387.                                                 (*(texp++)) = 0; // transparent pixel
  1388.                                                 break;
  1389. #if !DXX_USE_OGLES
  1390.                                         case GL_COLOR_INDEX:
  1391.                                                 (*(texp++)) = c;
  1392.                                                 break;
  1393. #endif
  1394.                                         default:
  1395.                                                 Error("ogl_filltexbuf unhandled super-transparent texformat\n");
  1396.                                                 break;
  1397.                                 }
  1398.                         }
  1399.                         else if ((c == 255 && (bm_flags & BM_FLAG_TRANSPARENT)) || c == 256)
  1400.                         {
  1401.                                 switch (type)
  1402.                                 {
  1403.                                         case GL_RGBA:
  1404.                                                 (*(texp++))=0;
  1405.                                                 DXX_BOOST_FALLTHROUGH;
  1406.                                         case GL_RGB:
  1407.                                                 (*(texp++))=0;
  1408.                                                 DXX_BOOST_FALLTHROUGH;
  1409.                                         case GL_LUMINANCE_ALPHA:
  1410.                                                 (*(texp++))=0;
  1411.                                                 DXX_BOOST_FALLTHROUGH;
  1412.                                         case GL_LUMINANCE:
  1413.                                                 (*(texp++))=0;//transparent pixel
  1414.                                                 break;
  1415. #if !DXX_USE_OGLES
  1416.                                         case GL_COLOR_INDEX:
  1417.                                                 (*(texp++)) = c;
  1418.                                                 break;
  1419. #endif
  1420.                                         default:
  1421.                                                 Error("ogl_filltexbuf unknown texformat\n");
  1422.                                                 break;
  1423.                                 }
  1424.                         }
  1425.                         else
  1426.                         {
  1427.                                 switch (type)
  1428.                                 {
  1429.                                         case GL_LUMINANCE_ALPHA:
  1430.                                                 (*(texp++))=255;
  1431.                                                 DXX_BOOST_FALLTHROUGH;
  1432.                                         case GL_LUMINANCE://these could prolly be done to make the intensity based upon the intensity of the resulting color, but its not needed for anything (yet?) so no point. :)
  1433.                                                 (*(texp++))=255;
  1434.                                                 break;
  1435.                                         case GL_RGB:
  1436.                                                 (*(texp++)) = pal[c].r * 4;
  1437.                                                 (*(texp++)) = pal[c].g * 4;
  1438.                                                 (*(texp++)) = pal[c].b * 4;
  1439.                                                 break;
  1440.                                         case GL_RGBA:
  1441.                                                 (*(texp++)) = pal[c].r * 4;
  1442.                                                 (*(texp++)) = pal[c].g * 4;
  1443.                                                 (*(texp++)) = pal[c].b * 4;
  1444.                                                 (*(texp++)) = 255;//not transparent
  1445.                                                 break;
  1446. #if !DXX_USE_OGLES
  1447.                                         case GL_COLOR_INDEX:
  1448.                                                 (*(texp++)) = c;
  1449.                                                 break;
  1450. #endif
  1451.                                         default:
  1452.                                                 Error("ogl_filltexbuf unknown texformat\n");
  1453.                                                 break;
  1454.                                 }
  1455.                         }
  1456.                 }
  1457.         }
  1458. }
  1459.  
  1460. static void tex_set_size1(ogl_texture &tex, const unsigned dbits, const unsigned bits, const unsigned w, const unsigned h)
  1461. {
  1462.         int u;
  1463.         if (tex.tw!=w || tex.th!=h){
  1464.                 u=(tex.w/static_cast<float>(tex.tw)*w) * (tex.h/static_cast<float>(tex.th)*h);
  1465.                 glmprintf((CON_DEBUG, "shrunken texture?"));
  1466.         }else
  1467.                 u=tex.w*tex.h;
  1468.         if (bits<=0){//the beta nvidia GLX server. doesn't ever return any bit sizes, so just use some assumptions.
  1469.                 tex.bytes=(static_cast<float>(w)*h*dbits)/8.0;
  1470.                 tex.bytesu=(static_cast<float>(u)*dbits)/8.0;
  1471.         }else{
  1472.                 tex.bytes=(static_cast<float>(w)*h*bits)/8.0;
  1473.                 tex.bytesu=(static_cast<float>(u)*bits)/8.0;
  1474.         }
  1475.         glmprintf((CON_DEBUG, "tex_set_size1: %ix%i, %ib(%i) %iB", w, h, bits, dbits, tex.bytes));
  1476. }
  1477.  
  1478. static void tex_set_size(ogl_texture &tex)
  1479. {
  1480.         GLint w,h;
  1481.         int bi=16,a=0;
  1482. #if !DXX_USE_OGLES
  1483.         if (CGameArg.DbgGlGetTexLevelParamOk)
  1484.         {
  1485.                 GLint t;
  1486.                 glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_WIDTH,&w);
  1487.                 glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_HEIGHT,&h);
  1488.                 glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_LUMINANCE_SIZE,&t);a+=t;
  1489.                 glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_INTENSITY_SIZE,&t);a+=t;
  1490.                 glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_RED_SIZE,&t);a+=t;
  1491.                 glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_GREEN_SIZE,&t);a+=t;
  1492.                 glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_BLUE_SIZE,&t);a+=t;
  1493.                 glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_ALPHA_SIZE,&t);a+=t;
  1494.         }
  1495.         else
  1496. #endif
  1497.         {
  1498.                 w=tex.tw;
  1499.                 h=tex.th;
  1500.         }
  1501.         switch (tex.format){
  1502.                 case GL_LUMINANCE:
  1503.                         bi=8;
  1504.                         break;
  1505.                 case GL_LUMINANCE_ALPHA:
  1506.                         bi=8;
  1507.                         break;
  1508.                 case GL_RGB:
  1509.                 case GL_RGBA:
  1510.                         bi=16;
  1511.                         break;
  1512. #if !DXX_USE_OGLES
  1513.                 case GL_COLOR_INDEX:
  1514.                         bi = 8;
  1515.                         break;
  1516. #endif
  1517.                 default:
  1518.                         throw std::runtime_error("unknown texture format");
  1519.         }
  1520.         tex_set_size1(tex,bi,a,w,h);
  1521. }
  1522.  
  1523. //loads a palettized bitmap into a ogl RGBA texture.
  1524. //Sizes and pads dimensions to multiples of 2 if necessary.
  1525. //In theory this could be a problem for repeating textures, but all real
  1526. //textures (not sprites, etc) in descent are 64x64, so we are ok.
  1527. //stores OpenGL textured id in *texid and u/v values required to get only the real data in *u/*v
  1528. static int ogl_loadtexture(const palette_array_t &pal, const uint8_t *data, const int dxo, int dyo, ogl_texture &tex, const int bm_flags, const int data_format, int texfilt, const bool texanis, const bool edgepad)
  1529. {
  1530.         tex.tw = pow2ize (tex.w);
  1531.         tex.th = pow2ize (tex.h);//calculate smallest texture size that can accomodate us (must be multiples of 2)
  1532.  
  1533.         //calculate u/v values that would make the resulting texture correctly sized
  1534.         tex.u = static_cast<float>(static_cast<double>(tex.w) / static_cast<double>(tex.tw));
  1535.         tex.v = static_cast<float>(static_cast<double>(tex.h) / static_cast<double>(tex.th));
  1536.  
  1537.         auto *bufP = texbuf.get();
  1538.         const uint8_t *outP = texbuf.get();
  1539.         {
  1540.                 if (bm_flags >= 0)
  1541.                         ogl_filltexbuf (pal, data, texbuf.get(), tex.lw, tex.w, tex.h, dxo, dyo, tex.tw, tex.th,
  1542.                                                                  tex.format, bm_flags, data_format);
  1543.                 else {
  1544.                         if (!dxo && !dyo && (tex.w == tex.tw) && (tex.h == tex.th))
  1545.                                 outP = data;
  1546.                         else {
  1547.                                 int h, w, tw;
  1548.  
  1549.                                 h = tex.lw / tex.w;
  1550.                                 w = (tex.w - dxo) * h;
  1551.                                 data += tex.lw * dyo + h * dxo;
  1552.                                
  1553.                                 tw = tex.tw * h;
  1554.                                 h = tw - w;
  1555.                                 for (; dyo < tex.h; dyo++, data += tex.lw) {
  1556.                                         memcpy (bufP, data, w);
  1557.                                         bufP += w;
  1558.                                         memset (bufP, 0, h);
  1559.                                         bufP += h;
  1560.                                 }
  1561.                                 memset (bufP, 0, tex.th * tw - (bufP - texbuf.get()));
  1562.                         }
  1563.                 }
  1564.         }
  1565.  
  1566.         //bleed color (rgb) into the alpha area, to deal with "dark edges problem"
  1567.         if ((tex.format == GL_RGBA) && texfilt && edgepad && !CGameArg.OglDarkEdges)
  1568.         {
  1569.                 GLubyte *p = bufP;
  1570.                 GLubyte *pdone = p + (4 * tex.tw * tex.th);
  1571.                 int line = 4 * tex.tw;
  1572.                 p += 4;
  1573.                 pdone -= 4;
  1574.                 GLubyte *ptop = p + line;
  1575.                 GLubyte *pbottom = pdone - line;
  1576.  
  1577.                 for (; p < pdone; p += 4)
  1578.                 {
  1579.                         //offsets 0 to 2 are r, g, b. offset 3 is alpha. 0x00 is transparent, 0xff is opaque.
  1580.                         if (! *(p + 3))
  1581.                         {
  1582.                                 if (*(p - 1))
  1583.                                 {
  1584.                                         *p = *(p - 4);
  1585.                                         *(p + 1) = *(p - 3);
  1586.                                         *(p + 2) = *(p - 2);
  1587.                                         continue;
  1588.                                 } //from left
  1589.                                 if (*(p + 7))
  1590.                                 {
  1591.                                         *p = *(p + 4);
  1592.                                         *(p + 1) = *(p + 5);
  1593.                                         *(p + 2) = *(p + 6);
  1594.                                         continue;
  1595.                                 } //from right
  1596.                                 if (p >= ptop)
  1597.                                 {
  1598.                                         if (*(p - line + 3))
  1599.                                         {
  1600.                                                 *p = *(p - line);
  1601.                                                 *(p + 1) = *(p - line + 1);
  1602.                                                 *(p + 2) = *(p - line + 2);
  1603.                                                 continue;
  1604.                                         } //from above
  1605.                                 }
  1606.                                 if (p < pbottom)
  1607.                                 {
  1608.                                         if (*(p + line + 3))
  1609.                                         {
  1610.                                                 *p = *(p + line);
  1611.                                                 *(p + 1) = *(p + line + 1);
  1612.                                                 *(p + 2) = *(p + line + 2);
  1613.                                                 continue;
  1614.                                         } //from below
  1615.                                         if (*(p + line - 1))
  1616.                                         {
  1617.                                                 *p = *(p + line - 4);
  1618.                                                 *(p + 1) = *(p + line - 3);
  1619.                                                 *(p + 2) = *(p + line - 2);
  1620.                                                 continue;
  1621.                                         } //bottom left
  1622.                                         if (*(p + line + 7))
  1623.                                         {
  1624.                                                 *p = *(p + line + 4);
  1625.                                                 *(p + 1) = *(p + line + 5);
  1626.                                                 *(p + 2) = *(p + line + 6);
  1627.                                                 continue;
  1628.                                         } //bottom right
  1629.                                 }
  1630.                                 if (p >= ptop)
  1631.                                 {
  1632.                                         if (*(p - line - 1))
  1633.                                         {
  1634.                                                 *p = *(p - line - 4);
  1635.                                                 *(p + 1) = *(p - line - 3);
  1636.                                                 *(p + 2) = *(p - line - 2);
  1637.                                                 continue;
  1638.                                         } //top left
  1639.                                         if (*(p - line + 7))
  1640.                                         {
  1641.                                                 *p = *(p - line + 4);
  1642.                                                 *(p + 1) = *(p - line + 5);
  1643.                                                 *(p + 2) = *(p - line + 6);
  1644.                                                 continue;
  1645.                                         } //top right
  1646.                                 }
  1647.                         }
  1648.                 }
  1649.         }
  1650.  
  1651.         int rescale = 1;
  1652.         if (texfilt == 1)
  1653.         {
  1654.                 rescale = 4;
  1655.                 if ((tex.tw > 256) || (tex.th > 256))
  1656.                 {
  1657.                         //don't scale big textures, instead "cheat" and render them as normal (nearest)
  1658.                         //these are normally 320x200 and 640x480 images.
  1659.                         //this deals with texture size limits, as well as large textures causing noticeable performance issues/hiccups.
  1660.                         texfilt = 0;
  1661.                         rescale = 1;
  1662.                 }
  1663.         }
  1664.         GLubyte *buftemp = NULL;
  1665.         if (rescale > 1)
  1666.         {
  1667.                 int rebpp = 3;
  1668.                 if (tex.format == GL_RGBA) rebpp = 4;
  1669.                 if (tex.format == GL_LUMINANCE) rebpp = 1;
  1670.                 MALLOC(buftemp,GLubyte,rescale*tex.tw*rescale*tex.th*rebpp);
  1671.                 int x,y;
  1672.                 GLubyte *p = buftemp;
  1673.                 int len = tex.tw*rebpp*rescale;
  1674.                 int bppscale = (rebpp*rescale);
  1675.  
  1676.                 for (y = 0; y < tex.th; y++)
  1677.                 {
  1678.                         GLubyte *p1 = bufP;
  1679.  
  1680.                         for (x = 0; x < len; x++)
  1681.                         {
  1682.                                 *(p+x) = *(outP + ((x / bppscale)*rebpp + (x % rebpp)));
  1683.                         }
  1684.                         p1 = p;
  1685.                         p += len;
  1686.                         int y2;
  1687.                         for (y2 = 1; y2 < rescale; y2++)
  1688.                         {
  1689.                                 memcpy (p, p1, len);
  1690.                                 p += len;
  1691.                         }
  1692.                         outP += tex.tw*rebpp;
  1693.                 }
  1694.                 outP = buftemp;
  1695.         }
  1696.  
  1697.         // Generate OpenGL texture IDs.
  1698.         glGenTextures (1, &tex.handle);
  1699. #if !DXX_USE_OGLES
  1700.         //set priority
  1701.         glPrioritizeTextures (1, &tex.handle, &tex.prio);
  1702. #endif
  1703.         // Give our data to OpenGL.
  1704.         OGL_BINDTEXTURE(tex.handle);
  1705.         glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1706.  
  1707.         // should match structue in menu.cpp
  1708.         // organized in switches for better readability
  1709.         bool buildmipmap = false;
  1710.         GLint gl_mag_filter_int, gl_min_filter_int;
  1711.         switch (texfilt)
  1712.         {
  1713.                 default:
  1714.                 case OGL_TEXFILT_CLASSIC: // Classic - Nearest
  1715.                         gl_mag_filter_int = GL_NEAREST;
  1716.                         if (texanis && ogl_maxanisotropy > 1.0f)
  1717.                         {
  1718.                                 // looks nicer if anisotropy is applied.
  1719.                                 gl_min_filter_int = GL_NEAREST_MIPMAP_LINEAR;
  1720.                                 buildmipmap = true;
  1721.                         }
  1722.                         else
  1723.                         {
  1724.                                 gl_min_filter_int = GL_NEAREST;
  1725.                                 buildmipmap = false;
  1726.                         }
  1727.                         break;
  1728.                 case OGL_TEXFILT_UPSCALE: // Upscaled - i.e. Blocky Filtered (Bilinear)
  1729.                 case OGL_TEXFILT_TRLINEAR: // Smooth - Trilinear
  1730.                         gl_mag_filter_int = GL_LINEAR;
  1731.                         gl_min_filter_int = GL_LINEAR_MIPMAP_LINEAR;
  1732.                         buildmipmap = true;
  1733.                         break;
  1734.         }
  1735.         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_mag_filter_int);
  1736.         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_min_filter_int);
  1737.         if (texanis && ogl_maxanisotropy > 1.0f)
  1738.                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, ogl_maxanisotropy);
  1739.  
  1740. #if DXX_USE_OGLES // in OpenGL ES 1.1 the mipmaps are automatically generated by a parameter
  1741.         glTexParameteri (GL_TEXTURE_2D, GL_GENERATE_MIPMAP, buildmipmap ? GL_TRUE : GL_FALSE);
  1742. #else
  1743.         if (buildmipmap)
  1744.         {
  1745.                 gluBuild2DMipmaps (
  1746.                                 GL_TEXTURE_2D, tex.internalformat,
  1747.                                 tex.tw * rescale, tex.th * rescale, tex.format,
  1748.                                 GL_UNSIGNED_BYTE,
  1749.                                 outP);
  1750.         }
  1751.         else
  1752. #endif
  1753.         {
  1754.                 glTexImage2D (
  1755.                         GL_TEXTURE_2D, 0, tex.internalformat,
  1756.                         tex.tw * rescale, tex.th * rescale, 0, tex.format, // RGBA textures.
  1757.                         GL_UNSIGNED_BYTE, // imageData is a GLubyte pointer.
  1758.                         outP);
  1759.         }
  1760.  
  1761.         tex_set_size(tex);
  1762.         if (buftemp)
  1763.                 d_free(buftemp);
  1764.         r_texcount++;
  1765.         return 0;
  1766. }
  1767.  
  1768. void ogl_loadbmtexture_f(grs_bitmap &rbm, int texfilt, bool texanis, bool edgepad)
  1769. {
  1770.         assert(!rbm.get_flag_mask(BM_FLAG_PAGED_OUT));
  1771.         assert(rbm.bm_data);
  1772.         grs_bitmap *bm = &rbm;
  1773.         while (const auto bm_parent = bm->bm_parent)
  1774.                 bm = bm_parent;
  1775.         if (bm->gltexture && bm->gltexture->handle > 0)
  1776.                 return;
  1777.         auto buf=bm->get_bitmap_data();
  1778.         const unsigned bm_w = bm->bm_w;
  1779.         if (bm->gltexture == NULL){
  1780.                 ogl_init_texture(*(bm->gltexture = ogl_get_free_texture()), bm_w, bm->bm_h, ((bm->get_flag_mask(BM_FLAG_TRANSPARENT | BM_FLAG_SUPER_TRANSPARENT)) ? OGL_FLAG_ALPHA : 0));
  1781.         }
  1782.         else {
  1783.                 if (bm->gltexture->handle>0)
  1784.                         return;
  1785.                 if (bm->gltexture->w==0){
  1786.                         bm->gltexture->lw = bm_w;
  1787.                         bm->gltexture->w = bm_w;
  1788.                         bm->gltexture->h=bm->bm_h;
  1789.                 }
  1790.         }
  1791.  
  1792.         std::array<uint8_t, 300*1024> decodebuf;
  1793.         if (bm->get_flag_mask(BM_FLAG_RLE))
  1794.         {
  1795.                 class bm_rle_expand_state
  1796.                 {
  1797.                         uint8_t *dbits;
  1798.                         uint8_t *const ebits;
  1799.                 public:
  1800.                         bm_rle_expand_state(uint8_t *const b, uint8_t *const e) :
  1801.                                 dbits(b), ebits(e)
  1802.                         {
  1803.                         }
  1804.                         uint8_t *get_begin_dbits() const
  1805.                         {
  1806.                                 return dbits;
  1807.                         }
  1808.                         uint8_t *get_end_dbits() const
  1809.                         {
  1810.                                 return ebits;
  1811.                         }
  1812.                         void consume_dbits(const unsigned w)
  1813.                         {
  1814.                                 dbits += w;
  1815.                         }
  1816.                 };
  1817.                 decodebuf = {};
  1818.                 buf = decodebuf.data();
  1819.                 if (!bm_rle_expand(*bm).loop(bm_w, bm_rle_expand_state(begin(decodebuf), end(decodebuf))))
  1820.                 {
  1821.                         con_printf(CON_URGENT, "error: insufficient space to decode %ux%hu bitmap.  Please report this as a bug.", bm_w, bm->bm_h);
  1822.                 }
  1823.         }
  1824.         ogl_loadtexture(gr_palette, buf, 0, 0, *bm->gltexture, bm->get_flags(), 0, texfilt, texanis, edgepad);
  1825. }
  1826.  
  1827. static void ogl_freetexture(ogl_texture &gltexture)
  1828. {
  1829.         if (gltexture.handle>0) {
  1830.                 r_texcount--;
  1831.                 glmprintf((CON_DEBUG, "ogl_freetexture(%p):%i (%i left)", &gltexture, gltexture.handle, r_texcount));
  1832.                 glDeleteTextures( 1, &gltexture.handle );
  1833. //              gltexture->handle=0;
  1834.                 ogl_reset_texture(gltexture);
  1835.         }
  1836. }
  1837.  
  1838. void ogl_freebmtexture(grs_bitmap &bm)
  1839. {
  1840.         if (auto &gltexture = bm.gltexture)
  1841.                 ogl_freetexture(*std::exchange(gltexture, nullptr));
  1842. }
  1843.  
  1844. const ogl_colors::array_type ogl_colors::white = {{
  1845.         1.0, 1.0, 1.0, 1.0,
  1846.         1.0, 1.0, 1.0, 1.0,
  1847.         1.0, 1.0, 1.0, 1.0,
  1848.         1.0, 1.0, 1.0, 1.0,
  1849. }};
  1850.  
  1851. const ogl_colors::array_type &ogl_colors::init_maybe_white(const int c)
  1852. {
  1853.         return c == -1 ? white : init_palette(c);
  1854. }
  1855.  
  1856. const ogl_colors::array_type &ogl_colors::init_palette(const unsigned c)
  1857. {
  1858.         const auto &rgb = gr_current_pal[c];
  1859.         const GLfloat r = rgb.r / 63.0, g = rgb.g / 63.0, b = rgb.b / 63.0;
  1860.         a = {{
  1861.                 r, g, b, 1.0,
  1862.                 r, g, b, 1.0,
  1863.                 r, g, b, 1.0,
  1864.                 r, g, b, 1.0,
  1865.         }};
  1866.         return a;
  1867. }
  1868.  
  1869. bool ogl_ubitmapm_cs(grs_canvas &canvas, int x, int y,int dw, int dh, grs_bitmap &bm,int c, int scale) // to scale bitmaps
  1870. {
  1871.         ogl_colors color;
  1872.         return ogl_ubitmapm_cs(canvas, x, y, dw, dh, bm, color.init(c), scale);
  1873. }
  1874.  
  1875. /*
  1876.  * Menu / gauges
  1877.  */
  1878. bool ogl_ubitmapm_cs(grs_canvas &canvas, int x, int y,int dw, int dh, grs_bitmap &bm, const ogl_colors::array_type &color_array, int scale) // to scale bitmaps
  1879. {
  1880.         GLfloat yo,xf,yf,u1,u2,v1,v2,h;
  1881.         ogl_client_states<GLfloat, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY> cs;
  1882.         auto &xo = std::get<0>(cs);
  1883.         x += canvas.cv_bitmap.bm_x;
  1884.         y += canvas.cv_bitmap.bm_y;
  1885.         xo=x/static_cast<float>(last_width);
  1886.         xf=(bm.bm_w+x)/static_cast<float>(last_width);
  1887.         yo=1.0-y/static_cast<float>(last_height);
  1888.         yf=1.0-(bm.bm_h+y)/static_cast<float>(last_height);
  1889.  
  1890.         if (dw < 0)
  1891.                 dw = canvas.cv_bitmap.bm_w;
  1892.         else if (dw == 0)
  1893.                 dw = bm.bm_w;
  1894.         if (dh < 0)
  1895.                 dh = canvas.cv_bitmap.bm_h;
  1896.         else if (dh == 0)
  1897.                 dh = bm.bm_h;
  1898.  
  1899.         h = static_cast<double>(scale) / static_cast<double>(F1_0);
  1900.  
  1901.         xo = x / (static_cast<double>(last_width) * h);
  1902.         xf = (dw + x) / (static_cast<double>(last_width) * h);
  1903.         yo = 1.0 - y / (static_cast<double>(last_height) * h);
  1904.         yf = 1.0 - (dh + y) / (static_cast<double>(last_height) * h);
  1905.  
  1906.         OGL_ENABLE(TEXTURE_2D);
  1907.         ogl_bindbmtex(bm, 0);
  1908.         ogl_texwrap(bm.gltexture,GL_CLAMP_TO_EDGE);
  1909.        
  1910.         if (bm.bm_x==0){
  1911.                 u1=0;
  1912.                 if (bm.bm_w==bm.gltexture->w)
  1913.                         u2=bm.gltexture->u;
  1914.                 else
  1915.                         u2=(bm.bm_w+bm.bm_x)/static_cast<float>(bm.gltexture->tw);
  1916.         }else {
  1917.                 u1=bm.bm_x/static_cast<float>(bm.gltexture->tw);
  1918.                 u2=(bm.bm_w+bm.bm_x)/static_cast<float>(bm.gltexture->tw);
  1919.         }
  1920.         if (bm.bm_y==0){
  1921.                 v1=0;
  1922.                 if (bm.bm_h==bm.gltexture->h)
  1923.                         v2=bm.gltexture->v;
  1924.                 else
  1925.                         v2=(bm.bm_h+bm.bm_y)/static_cast<float>(bm.gltexture->th);
  1926.         }else{
  1927.                 v1=bm.bm_y/static_cast<float>(bm.gltexture->th);
  1928.                 v2=(bm.bm_h+bm.bm_y)/static_cast<float>(bm.gltexture->th);
  1929.         }
  1930.  
  1931.         const std::array<GLfloat, 8> vertices{{
  1932.                 xo, yo,
  1933.                 xf, yo,
  1934.                 xf, yf,
  1935.                 xo, yf,
  1936.         }};
  1937.         const std::array<GLfloat, 8> texcoord_array{{
  1938.                 u1, v1,
  1939.                 u2, v1,
  1940.                 u2, v2,
  1941.                 u1, v2,
  1942.         }};
  1943.         glVertexPointer(2, GL_FLOAT, 0, vertices.data());
  1944.         glColorPointer(4, GL_FLOAT, 0, color_array.data());
  1945.         glTexCoordPointer(2, GL_FLOAT, 0, texcoord_array.data());
  1946.         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);//replaced GL_QUADS
  1947.         return 0;
  1948. }
  1949.  
  1950. }
  1951.