Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 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
}