summaryrefslogtreecommitdiff
path: root/src/game/world/bsp_draw.cpp
blob: 3f5b067cd171409aa752900324bb2f29f154ce60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include "bsp_draw.h"
#include "../../game.h"
#include "../../render/gl_3d.h"
#include "../objlist.h"
#include "bsp.h"
#include "map.h"
#include "trace.h"


void bsp_draw_leaf( BSP* bsp, GAME_DATA* game, I32 leafidx ) {
  BSP_LEAF* leaf = &bsp->leaves.data[leafidx];
  // todo : handle transparency

  for( U32 i = 0; i < leaf->count; ++i ) {
    BSP_FACE* f = &bsp->faces.data[leaf->first + i];
    U8 face_transparent = 0;
    if( !face_transparent ) {
      LIST<VERTEX3D> verts = f->render_verts;
      SURF_PROPS* props = bsp_face_get_props( game->state.map, f );
      gl_3d_polygon( game->render.batch_3d, verts.data, verts.size, props->tex );
    }
  }

  // todo : sort by depth
  for( U32 i = 0; i < leaf->count; ++i ) {
    BSP_FACE* f = &bsp->faces.data[leaf->first + i];
    U8 face_transparent = 0;
    if( face_transparent ) {
      LIST<VERTEX3D> verts = f->render_verts;
      SURF_PROPS* props = bsp_face_get_props( game->state.map, f );
      gl_3d_polygon( game->render.batch_3d, verts.data, verts.size, props->tex );
    }
  }
}

U8 leaf_visible( I32 leaf_idx ) {
  // todo : pvs
  return 1;
}

I32 bsp_point_leaf( BSP* bsp, const VEC3& p ) {
  I32 n = bsp->root;
  for( ;; ) {
    if( bsp_is_leaf( n ) ) return bsp_leaf_index( n );
    BSP_NODE* node = &bsp->nodes.data[n];
    F32 dist = bsp_plane_dist( node->plane, p );
    n = (dist >= 0.f)? node->front : node->back;
  }
}

void bsp_traverse_draw( BSP* bsp, GAME_DATA* game, I32 node, VEC3 campos ) {
  if( bsp_is_leaf( node ) ) {
    I32 i = bsp_leaf_index( node );
    return bsp_draw_leaf( bsp, game, i );
  }

  BSP_NODE* n = &bsp->nodes.data[node];
  F32 dist = bsp_plane_dist( n->plane, campos );

  I32 near = (dist >= 0.f)? n->front : n->back;
  I32 far  = (dist >= 0.f)? n->back : n->front;

  // todo : set up vertex buffer, draw all in one call
  // todo todo : batch different shader calls separately

  bsp_traverse_draw( bsp, game, near, campos );
  bsp_traverse_draw( bsp, game, far, campos );
}

void bsp_draw_sprites( BSP* bsp, GAME_DATA* game ) {
  LIST<MAP_SPRITE>* sprites = &game->state.map->sprites;
  for( U32 i = 0; i < sprites->size; ++i ) {
    MAP_SPRITE* sprite = &sprites->data[i];
    BSP_TRACE t{ .hitmask = HG_SOLID };
    t.in_start = player_get_view_pos( objl->pl );
    t.in_end = sprite->pos;

    bsp_trace( &t, bsp );
    if( !t.hit ) {
      VEC3 angle = vec_angles( sprite->pos, t.in_start );
      gl_3d_plane(
        game->shaders.gl3d,
        sprite->pos,
        sprite->size,
        { -angle.x + 90.f, angle.y - 90.f },
        sprite->tex,
        sprite->clr
      );
    }
  }
}

void bsp_draw( BSP* bsp, GAME_DATA* game, VEC2 window, VEC2 winsize ) {
  gl_set_viewport( game->gl, window, winsize );
  PLAYER* pl = objl->pl;
  F32 fov = pl->fov;
  gl_3d_projection_setup(
    game->shaders.gl3d,
    { pl->pos.x, pl->pos.y, pl->pos.z + pl->eyeoffset },
    fov,
    pl->rot.y,
    pl->rot.x,
    1.f,
    9999.f,
    winsize
  );

  gl_set_clip( game->gl, window, winsize );
  gl_batch_empty( game->render.batch_3d );
  glEnable( GL_DEPTH_TEST );
  glEnable( GL_CULL_FACE );
  // ???
  glFrontFace( GL_CW );
  glDepthFunc( GL_LESS );
  bsp_traverse_draw( bsp, game, bsp->root, objl->pl->pos );
  gl_batch_draw( game->render.batch_3d );

  glDisable( GL_DEPTH_TEST );
  glDisable( GL_CULL_FACE );
  bsp_draw_sprites( bsp, game );
  gl_reset_clip( game->gl );

  VEC2 canvas = { (F32)game->gl->canvas_size[0], (F32)game->gl->canvas_size[1] };
  gl_set_viewport( game->gl, {}, canvas );
}