File: decal_draw_list.cpp

package info (click to toggle)
freespace2 25.0.0~rc11%2Brepack-1
  • links: PTS, VCS
  • area: non-free
  • in suites: forky, sid
  • size: 47,232 kB
  • sloc: cpp: 657,500; ansic: 22,305; sh: 293; python: 200; makefile: 198; xml: 181
file content (149 lines) | stat: -rw-r--r-- 4,990 bytes parent folder | download
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include "graphics/decal_draw_list.h"

#include "graphics/matrix.h"

#include "render/3d.h"
#include "tracing/tracing.h"
#include "light.h"

namespace {

vec3d BOX_VERTS[] = {{{{ -0.5f, -0.5f, -0.5f }}},
					 {{{ -0.5f, 0.5f,  -0.5f }}},
					 {{{ 0.5f,  0.5f,  -0.5f }}},
					 {{{ 0.5f,  -0.5f, -0.5f }}},
					 {{{ -0.5f, -0.5f, 0.5f }}},
					 {{{ -0.5f, 0.5f,  0.5f }}},
					 {{{ 0.5f,  0.5f,  0.5f }}},
					 {{{ 0.5f,  -0.5f, 0.5f }}}};

uint32_t BOX_FACES[] =
	{ 7, 3, 4, 3, 0, 4, 2, 6, 1, 6, 5, 1, 7, 6, 3, 6, 2, 3, 0, 1, 4, 1, 5, 4, 6, 7, 4, 5, 6, 4, 3, 2, 0, 2, 1, 0, };

const size_t BOX_NUM_FACES = sizeof(BOX_FACES) / sizeof(BOX_FACES[0]);

gr_buffer_handle box_vertex_buffer;
gr_buffer_handle box_index_buffer;
gr_buffer_handle decal_instance_buffer;

void init_buffers() {
	box_vertex_buffer = gr_create_buffer(BufferType::Vertex, BufferUsageHint::Static);
	gr_update_buffer_data(box_vertex_buffer, sizeof(BOX_VERTS), BOX_VERTS);

	box_index_buffer = gr_create_buffer(BufferType::Index, BufferUsageHint::Static);
	gr_update_buffer_data(box_index_buffer, sizeof(BOX_FACES), BOX_FACES);

	decal_instance_buffer = gr_create_buffer(BufferType::Vertex, BufferUsageHint::Streaming);
}

bool check_box_in_view(const matrix4& transform) {
	for (auto& point : BOX_VERTS) {
		vec3d pt;
		vm_vec_transform(&pt, &point, &transform, true);
		vec3d tmp;
		if (!g3_rotate_vector(&tmp, &pt)) {
			// This point lies in the view cone so we need to render it
			return true;
		}
	}

	return false;
}

}

namespace graphics {

void decal_draw_list::globalInit() {
	init_buffers();

	gr_maybe_create_shader(SDR_TYPE_DECAL, 0);
	gr_maybe_create_shader(SDR_TYPE_DECAL, SDR_FLAG_DECAL_USE_NORMAL_MAP);
}
void decal_draw_list::globalShutdown() {
	gr_delete_buffer(box_vertex_buffer);
	gr_delete_buffer(box_index_buffer);
}

void decal_draw_list::prepare_global_data() {
	_buffer       = gr_get_uniform_buffer(uniform_block_type::DecalInfo, _draws.size());
	auto& aligner = _buffer.aligner();

	// Initialize header data
	auto header = aligner.getHeader<graphics::decal_globals>();
	matrix4 invView;
	vm_inverse_matrix4(&invView, &gr_view_matrix);

	header->viewMatrix = gr_view_matrix;
	header->projMatrix = gr_projection_matrix;
	header->invViewMatrix = invView;
	vm_inverse_matrix4(&header->invProjMatrix, &gr_projection_matrix);

	header->viewportSize.x = (float) gr_screen.max_w;
	header->viewportSize.y = (float) gr_screen.max_h;

	for (auto& [batch_info, draw_info] : _draws) {
		auto info = aligner.addTypedElement<graphics::decal_info>();
		info->diffuse_index = batch_info.diffuse < 0 ? -1 : bm_get_array_index(batch_info.diffuse);
		info->glow_index = batch_info.glow < 0 ? -1 : bm_get_array_index(batch_info.glow);
		info->normal_index = batch_info.normal < 0 ? -1 : bm_get_array_index(batch_info.normal);

		draw_info.first.uniform_offset = _buffer.getBufferOffset(aligner.getCurrentOffset());

		material_set_decal(&draw_info.first.material,
						   bm_get_base_frame(batch_info.diffuse),
						   bm_get_base_frame(batch_info.glow),
						   bm_get_base_frame(batch_info.normal));
		info->diffuse_blend_mode = draw_info.first.material.get_blend_mode(0) == ALPHA_BLEND_ADDITIVE ? 1 : 0;
		info->glow_blend_mode = draw_info.first.material.get_blend_mode(2) == ALPHA_BLEND_ADDITIVE ? 1 : 0;
	}
}

void decal_draw_list::render() {
	GR_DEBUG_SCOPE("Render decals");
	TRACE_SCOPE(tracing::RenderDecals);

	prepare_global_data();

	_buffer.submitData();

	vertex_layout layout;
	layout.add_vertex_component(vertex_format_data::POSITION3, sizeof(vec3d), 0);
	layout.add_vertex_component(vertex_format_data::MATRIX4, sizeof(matrix4), 0, 1, 1);

	indexed_vertex_source source;
	source.Vbuffer_handle = box_vertex_buffer;
	source.Ibuffer_handle = box_index_buffer;

	// Bind the global data only once
	gr_bind_uniform_buffer(uniform_block_type::DecalGlobals,
		_buffer.getBufferOffset(0),
		sizeof(graphics::decal_globals),
		_buffer.bufferHandle());
	gr_screen.gf_start_decal_pass();

	for (auto& [textures, decal_list] : _draws) {
		GR_DEBUG_SCOPE("Draw decal type");
		TRACE_SCOPE(tracing::RenderSingleDecal);

		gr_update_buffer_data(decal_instance_buffer, sizeof(matrix4) * decal_list.second.size(), decal_list.second.data());
		gr_bind_uniform_buffer(uniform_block_type::DecalInfo, decal_list.first.uniform_offset, sizeof(graphics::decal_info), _buffer.bufferHandle());
		gr_screen.gf_render_decals(&decal_list.first.material, PRIM_TYPE_TRIS, &layout, BOX_NUM_FACES, source, decal_instance_buffer, static_cast<int>(decal_list.second.size()));
	}

	gr_screen.gf_stop_decal_pass();
}
void decal_draw_list::add_decal(int diffuse_bitmap,
								int glow_bitmap,
								int normal_bitmap,
								float  /*decal_timer*/,
								const matrix4& instancedata) {
	if (!check_box_in_view(instancedata)) {
		// The decal box is not in view so we don't need to render it
		return;
	}

	_draws[decal_batch_info{diffuse_bitmap, glow_bitmap, normal_bitmap}].second.emplace_back(instancedata);
}

}