OpenGL ES SDK for Android ARM Developer Center
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GroundMesh.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2014-2017, ARM Limited and Contributors
2  *
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge,
6  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
21 #include "GroundMesh.h"
22 #include <cstdio>
23 #include <cassert>
24 #include <cstdint>
25 #include "Platform.h"
26 #include "AABB.h"
27 
28 using namespace MaliSDK;
29 using namespace std;
30 
31 GroundMesh::GroundMesh(unsigned int size, unsigned int levels, float clip_scale)
32  : size(size), level_size(4 * size - 1), levels(levels), clipmap_scale(clip_scale)
33 {
34  setup_vertex_buffer(size);
35  setup_index_buffer(size);
36  setup_block_ranges(size);
38 
40 
41  // UBOs must be bound with aligned length and offset, and it varies per vendor.
42  GL_CHECK(glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_align));
43 }
44 
46 {
47  GL_CHECK(glDeleteBuffers(1, &vertex_buffer));
48  GL_CHECK(glDeleteBuffers(1, &index_buffer));
49  GL_CHECK(glDeleteBuffers(1, &uniform_buffer));
50  GL_CHECK(glDeleteVertexArrays(1, &vertex_array));
51 }
52 
54 // The clipmap levels only move in steps of texture coordinates.
55 // Computes top-left world position for the levels.
56 vec2 GroundMesh::get_offset_level(const vec2& camera_pos, unsigned int level)
57 {
58  if (level == 0) // Must follow level 1 as trim region is fixed.
59  return get_offset_level(camera_pos, 1) + vec2(size << 1);
60  else
61  {
62  vec2 scaled_pos = camera_pos / vec2(clipmap_scale); // Snap to grid in the appropriate space.
63 
64  // Snap to grid of next level. I.e. we move the clipmap level in steps of two.
65  vec2 snapped_pos = vec_floor(scaled_pos / vec2(1 << (level + 1))) * vec2(1 << (level + 1));
66 
67  // Apply offset so all levels align up neatly.
68  // If snapped_pos is equal for all levels,
69  // this causes top-left vertex of level N to always align up perfectly with top-left interior corner of level N + 1.
70  // This gives us a bottom-right trim region.
71 
72  // Due to the flooring, snapped_pos might not always be equal for all levels.
73  // The flooring has the property that snapped_pos for level N + 1 is less-or-equal snapped_pos for level N.
74  // If less, the final position of level N + 1 will be offset by -2 ^ N, which can be compensated for with changing trim-region to top-left.
75  vec2 pos = snapped_pos - vec2((2 * (size - 1)) << level);
76  return pos;
77  }
78 }
80 
81 void GroundMesh::update_level_offsets(const vec2& camera_pos)
82 {
83  level_offsets.resize(levels);
84  for (unsigned int i = 0; i < levels; i++)
85  level_offsets[i] = get_offset_level(camera_pos, i);
86 }
87 
88 // Since we use instanced drawing, all the different instances of various block types
89 // can be grouped together to form one draw call per block type.
90 //
91 // For the get_draw_info* calls, we look through all possible places where blocks can be rendered
92 // and push this information to a draw list and a uniform buffer.
93 //
94 // The draw list struct (DrawInfo) contains information such as the number of instances for a block type,
95 // and from where in the uniform buffer to get per-instance data. The per-instance data contains information
96 // of offset and scale values required to render the blocks at correct positions and at correct scale.
97 //
98 // The get_draw_info_* calls are sort of repetitive so comments are only introduced when
99 // something different is done.
100 //
101 // It is important to note that instance.offset is a pre-scaled offset which denotes the
102 // world-space X/Z position of the top-left vertex in the block.
103 // instance.scale is used to scale vertex data in a block (which are just integers).
104 //
105 // World space X/Z coordinates are computed as instance.offset + vertex_coord * instance.scale.
106 
108 {
109  DrawInfo info;
110  InstanceData instance;
111 
112  // Horizontal
114  info.indices = horizontal.count;
115  info.instances = 0;
116 
117  // We don't have any fixup regions for the lowest clipmap level.
118  for (unsigned int i = 1; i < levels; i++)
119  {
120  // Left side horizontal fixup region.
121  // Texel coordinates are derived by just dividing the world space offset with texture size.
122  // The 0.5 texel offset required to sample exactly at the texel center is done in vertex shader.
123  instance.texture_scale = 1.0f / level_size;
124  instance.scale = clipmap_scale * float(1 << i);
125  instance.level = i;
126 
127  instance.offset = level_offsets[i];
128  instance.offset += vec2(0, 2 * (size - 1)) * vec2(1 << i);
129  // Avoid texture coordinates which are very large as this can be difficult for the texture sampler
130  // to handle (float precision). Since we use GL_REPEAT, fract() does not change the result.
131  // Scale the offset down by 2^level first to get the appropriate texel.
132  instance.texture_offset = vec_fract((instance.offset / vec2(1 << i)) * instance.texture_scale);
133  instance.offset *= vec2(clipmap_scale);
134 
135  // Only add the instance if it's visible.
136  if (intersects_frustum(instance.offset, horizontal.range, i))
137  {
138  *instances++ = instance;
139  info.instances++;
140  }
141 
142  // Right side horizontal fixup region.
143  instance.offset = level_offsets[i];
144  instance.offset += vec2(3 * (size - 1) + 2, 2 * (size - 1)) * vec2(1 << i);
145  instance.texture_offset = vec_fract((instance.offset / vec2(1 << i)) * instance.texture_scale);
146  instance.offset *= vec2(clipmap_scale);
147 
148  // Only add the instance if it's visible.
149  if (intersects_frustum(instance.offset, horizontal.range, i))
150  {
151  *instances++ = instance;
152  info.instances++;
153  }
154  }
155 
156  return info;
157 }
158 
159 // Same as horizontal, just different vertex data and offsets.
161 {
162  DrawInfo info;
163  InstanceData instance;
164 
165  // Vertical
167  info.indices = vertical.count;
168  info.instances = 0;
169 
170  for (unsigned int i = 1; i < levels; i++)
171  {
172  // Top region
173  instance.texture_scale = 1.0f / level_size;
174  instance.scale = clipmap_scale * float(1 << i);
175  instance.level = i;
176 
177  instance.offset = level_offsets[i];
178  instance.offset += vec2(2 * (size - 1), 0) * vec2(1 << i);
179  instance.texture_offset = vec_fract((instance.offset / vec2(1 << i)) * instance.texture_scale);
180  instance.offset *= vec2(clipmap_scale);
181 
182  if (intersects_frustum(instance.offset, vertical.range, i))
183  {
184  *instances++ = instance;
185  info.instances++;
186  }
187 
188  // Bottom region
189  instance.offset = level_offsets[i];
190  instance.offset += vec2(2 * (size - 1), 3 * (size - 1) + 2) * vec2(1 << i);
191  instance.texture_offset = vec_fract((instance.offset / vec2(1 << i)) * instance.texture_scale);
192  instance.offset *= vec2(clipmap_scale);
193 
194  if (intersects_frustum(instance.offset, vertical.range, i))
195  {
196  *instances++ = instance;
197  info.instances++;
198  }
199  }
200 
201  return info;
202 }
203 
204 GroundMesh::DrawInfo GroundMesh::get_draw_info_degenerate(InstanceData *instances, const Block& block, const vec2& offset, const vec2& ring_offset)
205 {
206  DrawInfo info;
207  info.instances = 0;
208  info.index_buffer_offset = block.offset;
209  info.indices = block.count;
210  InstanceData instance;
211  instance.texture_scale = 1.0f / level_size;
212 
213  // No need to connect the last clipmap level to next level (there is none).
214  for (unsigned int i = 0; i < levels - 1; i++)
215  {
216  instance.level = i;
217  instance.offset = level_offsets[i];
218  instance.offset += offset * vec2(1 << i);
219 
220  // This is required to differentiate between level 0 and the other levels.
221  // In clipmap level 0, we only have tightly packed N-by-N blocks.
222  // In other levels however, there are horizontal and vertical fixup regions, therefore a different
223  // offset (2 extra texels) is required.
224  if (i > 0)
225  instance.offset += ring_offset * vec2(1 << i);
226  instance.texture_offset = vec_fract((instance.offset / vec2(1 << i)) * instance.texture_scale);
227  instance.offset *= vec2(clipmap_scale);
228  instance.scale = clipmap_scale * float(1 << i);
229 
230  if (intersects_frustum(instance.offset, block.range, i))
231  {
232  *instances++ = instance;
233  info.instances++;
234  }
235  }
236 
237  return info;
238 }
239 
240 // Use the generalized get_draw_info_degenerate().
242 {
243  return get_draw_info_degenerate(instances, degenerate_left, vec2(0.0f), vec2(0.0f));
244 }
245 
247 {
248  return get_draw_info_degenerate(instances, degenerate_right, vec2(4 * (size - 1), 0.0f), vec2(2.0f, 0.0f));
249 }
250 
252 {
253  return get_draw_info_degenerate(instances, degenerate_top, vec2(0.0f), vec2(0.0f));
254 }
255 
257 {
258  return get_draw_info_degenerate(instances, degenerate_bottom, vec2(0.0f, 4 * (size - 1) + 2), vec2(0.0f, 2.0f));
259 }
260 
261 // Only used for cliplevel 1 to encapsulate cliplevel 0.
263 {
264  DrawInfo info;
266  info.indices = trim_full.count;
267  info.instances = 0;
268 
269  InstanceData instance;
270  instance.texture_scale = 1.0f / level_size;
271  instance.level = 1;
272  instance.offset = level_offsets[1];
273  instance.offset += vec2((size - 1) << 1);
274  instance.texture_offset = vec_fract((instance.offset / vec2(1 << 1)) * instance.texture_scale);
275  instance.offset *= vec2(clipmap_scale);
276  instance.scale = clipmap_scale * float(1 << 1);
277 
278  if (intersects_frustum(instance.offset, trim_full.range, 1))
279  {
280  *instances = instance;
281  info.instances++;
282  }
283 
284  return info;
285 }
286 
287 GroundMesh::DrawInfo GroundMesh::get_draw_info_trim(InstanceData *instances, const Block& block, TrimConditional cond)
288 {
289  DrawInfo info;
290  info.index_buffer_offset = block.offset;
291  info.indices = block.count;
292  info.instances = 0;
293 
294  // Level 1 always fills in the gap to level 0 using get_draw_info_trim_full().
295  // From level 2 and out, we only need a single L-shaped trim region as levels 1 and up
296  // use horizontal/vertical trim regions as well, which increases the size slightly (get_draw_info_blocks()).
297  for (unsigned int i = 2; i < levels; i++)
298  {
299  vec2 offset_prev_level = level_offsets[i - 1];
300  vec2 offset_current_level = level_offsets[i] + vec2((size - 1) << i);
301 
302  // There are four different ways (top-right, bottom-right, top-left, bottom-left)
303  // to apply a trim region depending on how camera snapping is done in get_offset_level().
304  // A function pointer is introduced here so we can check if a particular trim type
305  // should be used for this level. Only one conditional will return true for a given level.
306  if (!cond(offset_prev_level - offset_current_level))
307  continue;
308 
309  InstanceData instance;
310  instance.texture_scale = 1.0f / level_size;
311  instance.level = i;
312  instance.offset = level_offsets[i];
313  instance.offset += vec2((size - 1) << i);
314  instance.texture_offset = vec_fract((instance.offset / vec2(1 << i)) * instance.texture_scale);
315  instance.offset *= vec2(clipmap_scale);
316  instance.scale = clipmap_scale * float(1 << i);
317 
318  if (intersects_frustum(instance.offset, block.range, i))
319  {
320  *instances++ = instance;
321  info.instances++;
322  }
323  }
324 
325  return info;
326 }
327 
328 // offset.x and offset.y are either 0 or at least 1.
329 // Using 0.5f as threshold is a safe way to check for this difference.
330 static inline bool trim_top_right_cond(const vec2& offset)
331 {
332  return offset.c.x < 0.5f && offset.c.y > 0.5f;
333 }
334 
335 static inline bool trim_top_left_cond(const vec2& offset)
336 {
337  return offset.c.x > 0.5f && offset.c.y > 0.5f;
338 }
339 
340 static inline bool trim_bottom_right_cond(const vec2& offset)
341 {
342  return offset.c.x < 0.5f && offset.c.y < 0.5f;
343 }
344 
345 static inline bool trim_bottom_left_cond(const vec2& offset)
346 {
347  return offset.c.x > 0.5f && offset.c.y < 0.5f;
348 }
349 
351 {
353 }
354 
356 {
358 }
359 
361 {
363 }
364 
366 {
368 }
369 
370 // These are the basic N-by-N tesselated quads.
372 {
373  // Special case for level 0, here we draw the base quad in a tight 4x4 grid. This needs to be padded with a full trim (get_draw_info_trim_full()).
374  DrawInfo info;
375  info.instances = 0;
377  info.indices = block.count;
378 
379  InstanceData instance;
380  instance.scale = clipmap_scale;
381  instance.texture_scale = 1.0f / level_size;
382 
383  for (unsigned int z = 0; z < 4; z++)
384  {
385  for (unsigned int x = 0; x < 4; x++)
386  {
387  instance.level = 0;
388  instance.offset = level_offsets[0];
389  instance.offset += vec2(x, z) * vec2(size - 1);
390  instance.texture_offset = vec_fract(instance.offset * instance.texture_scale);
391  instance.offset *= vec2(clipmap_scale);
392 
393  if (intersects_frustum(instance.offset, block.range, 0))
394  {
395  *instances++ = instance;
396  info.instances++;
397  }
398  }
399  }
400 
401  // From level 1 and out, the four center blocks are already filled with the lower clipmap level, so
402  // skip these.
403  for (unsigned int i = 1; i < levels; i++)
404  {
405  instance.texture_scale = 1.0f / level_size;
406 
407  for (unsigned int z = 0; z < 4; z++)
408  {
409  for (unsigned int x = 0; x < 4; x++)
410  {
411  if (z != 0 && z != 3 && x != 0 && x != 3)
412  {
413  // Already occupied, skip.
414  continue;
415  }
416 
417  instance.scale = clipmap_scale * float(1 << i);
418  instance.level = i;
419  instance.offset = level_offsets[i];
420  instance.offset += vec2(x, z) * vec2((size - 1) << i);
421 
422  // Skip 2 texels horizontally and vertically at the middle to get a symmetric structure.
423  // These regions are filled with horizontal and vertical fixup regions.
424  if (x >= 2)
425  instance.offset.c.x += 2 << i;
426  if (z >= 2)
427  instance.offset.c.y += 2 << i;
428 
429  instance.texture_offset = vec_fract((instance.offset / vec2(1 << i)) * instance.texture_scale);
430  instance.offset *= vec2(clipmap_scale);
431 
432  if (intersects_frustum(instance.offset, block.range, i))
433  {
434  *instances++ = instance;
435  info.instances++;
436  }
437  }
438  }
439  }
440 
441  return info;
442 }
443 
444 bool GroundMesh::intersects_frustum(const vec2& offset, const vec2& range, unsigned int level)
445 {
446  // These depend on the heightmap itself. These should be as small as possible to be able to cull more blocks.
447  // We know the range of the block in the XZ-plane, but not in Y as it depends on the heightmap texture.
448  // In the vertex shader, we enforce a min/max height, so it is safe to assume a range for Y.
449  float y_min = -20.0f;
450  float y_max = 20.0f;
451 
452  // Create an axis-aligned bounding box.
453  // Add a twiddle factor to account for potential precision issues.
454  AABB aabb(vec3(offset.c.x, y_min, offset.c.y) + vec3(-0.01f),
455  vec3(range.c.x, 0.0f, range.c.y) * vec3(float(1 << level)) * vec3(clipmap_scale) + vec3(0, y_max - y_min, 0) + vec3(0.02f));
456 
457  return view_proj_frustum.intersects_aabb(aabb);
458 }
459 
460 // Helper template to keep the ugly pointer casting to one place.
461 template<typename T>
462 static inline T *buffer_offset(T *buffer, size_t offset)
463 {
464  return reinterpret_cast<T*>(reinterpret_cast<uint8_t*>(buffer) + offset);
465 }
466 
467 // Round up to nearest aligned offset.
468 static inline unsigned int realign_offset(size_t offset, size_t align)
469 {
470  return (offset + align - 1) & ~(align - 1);
471 }
472 
473 void GroundMesh::update_draw_list(DrawInfo& info, size_t& uniform_buffer_offset)
474 {
475  info.uniform_buffer_offset = uniform_buffer_offset;
476  draw_list.push_back(info);
477 
478  // Have to ensure that the uniform buffer is always bound at aligned offsets.
479  uniform_buffer_offset = realign_offset(uniform_buffer_offset + info.instances * sizeof(InstanceData), uniform_buffer_align);
480 }
481 
483 {
484  draw_list.clear();
485 
486  GL_CHECK(glBindBuffer(GL_UNIFORM_BUFFER, uniform_buffer));
487 
488  // Map the uniform buffer.
489  GL_CHECK(InstanceData *data = static_cast<InstanceData*>(glMapBufferRange(GL_UNIFORM_BUFFER,
490  0, uniform_buffer_size, GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_WRITE_BIT)));
491 
492  if (!data)
493  {
494  LOGE("Failed to map uniform buffer.\n");
495  return;
496  }
497 
498  DrawInfo info;
499  size_t uniform_buffer_offset = 0;
500 
501  // Create a draw list. The number of draw calls is equal to the different types
502  // of blocks. The blocks are instanced as necessary in the get_draw_info* calls.
503 
504  // Main blocks
505  info = get_draw_info_blocks(buffer_offset(data, uniform_buffer_offset));
506  update_draw_list(info, uniform_buffer_offset);
507 
508  // Vertical ring fixups
509  info = get_draw_info_vert_fixup(buffer_offset(data, uniform_buffer_offset));
510  update_draw_list(info, uniform_buffer_offset);
511 
512  // Horizontal ring fixups
513  info = get_draw_info_horiz_fixup(buffer_offset(data, uniform_buffer_offset));
514  update_draw_list(info, uniform_buffer_offset);
515 
516  // Left-side degenerates
517  info = get_draw_info_degenerate_left(buffer_offset(data, uniform_buffer_offset));
518  update_draw_list(info, uniform_buffer_offset);
519 
520  // Right-side degenerates
521  info = get_draw_info_degenerate_right(buffer_offset(data, uniform_buffer_offset));
522  update_draw_list(info, uniform_buffer_offset);
523 
524  // Top-side degenerates
525  info = get_draw_info_degenerate_top(buffer_offset(data, uniform_buffer_offset));
526  update_draw_list(info, uniform_buffer_offset);
527 
528  // Bottom-side degenerates
529  info = get_draw_info_degenerate_bottom(buffer_offset(data, uniform_buffer_offset));
530  update_draw_list(info, uniform_buffer_offset);
531 
532  // Full trim
533  info = get_draw_info_trim_full(buffer_offset(data, uniform_buffer_offset));
534  update_draw_list(info, uniform_buffer_offset);
535 
536  // Top-right trim
537  info = get_draw_info_trim_top_right(buffer_offset(data, uniform_buffer_offset));
538  update_draw_list(info, uniform_buffer_offset);
539 
540  // Top-left trim
541  info = get_draw_info_trim_top_left(buffer_offset(data, uniform_buffer_offset));
542  update_draw_list(info, uniform_buffer_offset);
543 
544  // Bottom-right trim
545  info = get_draw_info_trim_bottom_right(buffer_offset(data, uniform_buffer_offset));
546  update_draw_list(info, uniform_buffer_offset);
547 
548  // Bottom-left trim
549  info = get_draw_info_trim_bottom_left(buffer_offset(data, uniform_buffer_offset));
550  update_draw_list(info, uniform_buffer_offset);
551 
552  GL_CHECK(glUnmapBuffer(GL_UNIFORM_BUFFER));
553 }
554 
557 {
558  for (std::vector<DrawInfo>::const_iterator itr = draw_list.begin(); itr != draw_list.end(); ++itr)
559  {
560  if (!itr->instances)
561  continue;
562 
563  // Bind uniform buffer at correct offset.
564  GL_CHECK(glBindBufferRange(GL_UNIFORM_BUFFER, 0, uniform_buffer,
565  itr->uniform_buffer_offset, realign_offset(itr->instances * sizeof(InstanceData), uniform_buffer_align)));
566 
567  // Draw all instances.
568  GL_CHECK(glDrawElementsInstanced(GL_TRIANGLE_STRIP, itr->indices, GL_UNSIGNED_SHORT,
569  reinterpret_cast<const GLvoid*>(itr->index_buffer_offset * sizeof(GLushort)), itr->instances));
570  }
571 }
573 
576 {
577  // Create a draw-list.
579 
580  // Explicitly bind and unbind GL state to ensure clarity.
581  GL_CHECK(glBindVertexArray(vertex_array));
583  GL_CHECK(glBindVertexArray(0));
584  GL_CHECK(glBindBuffer(GL_UNIFORM_BUFFER, 0));
585  GL_CHECK(glBindBufferBase(GL_UNIFORM_BUFFER, 0, 0));
586 }
T vec_fract(const T &vec)
Definition: vector_math.h:328
T vec_floor(const T &vec)
Definition: vector_math.h:310
DrawInfo get_draw_info_vert_fixup(InstanceData *instance_data)
Definition: GroundMesh.cpp:160
bool intersects_aabb(const AABB &aabb) const
[Compute plane equations]
Definition: Frustum.cpp:85
vec2 get_offset_level(const vec2 &camera_pos, unsigned int level)
[Snapping clipmap level to a grid]
Definition: GroundMesh.cpp:56
void setup_vertex_buffer(unsigned int size)
void setup_block_ranges(unsigned int size)
[Generating index buffer]
Block trim_full
Definition: GroundMesh.h:71
unsigned int levels
Definition: GroundMesh.h:46
static bool trim_bottom_right_cond(const vec2 &offset)
Definition: GroundMesh.cpp:340
Block horizontal
Definition: GroundMesh.h:70
unsigned int indices
Definition: GroundMesh.h:93
Definition: matrix.h:51
GLsizei range
Definition: gl2ext.h:2467
DrawInfo get_draw_info_degenerate_top(InstanceData *instance_data)
Definition: GroundMesh.cpp:251
GLint uniform_buffer_align
Definition: GroundMesh.h:97
DrawInfo get_draw_info_trim_bottom_left(InstanceData *instance_data)
Definition: GroundMesh.cpp:365
GLuint vertex_array
Definition: GroundMesh.h:43
GLuint index_buffer
Definition: GroundMesh.h:43
Definition: matrix.h:28
GLenum GLuint GLintptr offset
Definition: gl2ext.h:629
static bool trim_top_left_cond(const vec2 &offset)
Definition: GroundMesh.cpp:335
Frustum view_proj_frustum
Definition: GroundMesh.h:122
DrawInfo get_draw_info_degenerate_bottom(InstanceData *instance_data)
Definition: GroundMesh.cpp:256
Block degenerate_right
Definition: GroundMesh.h:78
void setup_uniform_buffer()
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
Definition: gl2ext.h:179
float clipmap_scale
Definition: GroundMesh.h:50
DrawInfo get_draw_info_trim_top_left(InstanceData *instance_data)
Definition: GroundMesh.cpp:355
size_t uniform_buffer_offset
Definition: GroundMesh.h:92
DrawInfo get_draw_info_degenerate_left(InstanceData *instance_data)
Definition: GroundMesh.cpp:241
DrawInfo get_draw_info_horiz_fixup(InstanceData *instance_data)
Definition: GroundMesh.cpp:107
GLuint uniform_buffer
Definition: GroundMesh.h:43
void update_level_offsets(const vec2 &camera_pos)
[Snapping clipmap level to a grid]
Definition: GroundMesh.cpp:81
DrawInfo get_draw_info_degenerate_right(InstanceData *instance_data)
Definition: GroundMesh.cpp:246
DrawInfo get_draw_info_trim(InstanceData *instance_data, const Block &block, TrimConditional cond)
Definition: GroundMesh.cpp:287
DrawInfo get_draw_info_degenerate(InstanceData *instance_data, const Block &block, const vec2 &offset, const vec2 &ring_offset)
Definition: GroundMesh.cpp:204
Block trim_top_right
Definition: GroundMesh.h:72
void update_draw_list()
Definition: GroundMesh.cpp:482
Block block
Definition: GroundMesh.h:68
Block trim_bottom_left
Definition: GroundMesh.h:74
size_t index_buffer_offset
Definition: GroundMesh.h:91
Block trim_top_left
Definition: GroundMesh.h:75
DrawInfo get_draw_info_trim_top_right(InstanceData *instance_data)
Definition: GroundMesh.cpp:350
void setup_index_buffer(unsigned int size)
GLfloat GLfloat f
Definition: gl2ext.h:2707
GroundMesh(unsigned int size, unsigned int levels, float clip_scale)
Definition: GroundMesh.cpp:31
#define GL_CHECK(x)
Definition: AstcTextures.h:59
Block degenerate_top
Definition: GroundMesh.h:77
void render()
[Rendering the entire terrain]
Definition: GroundMesh.cpp:575
DrawInfo get_draw_info_blocks(InstanceData *instance_data)
Definition: GroundMesh.cpp:371
struct vec2::@27::@30 c
unsigned int level_size
Definition: GroundMesh.h:45
static unsigned int realign_offset(size_t offset, size_t align)
Definition: GroundMesh.cpp:468
static bool trim_bottom_left_cond(const vec2 &offset)
Definition: GroundMesh.cpp:345
GLsizei levels
Definition: gl2ext.h:1816
void setup_vertex_array()
std::vector< DrawInfo > draw_list
Definition: GroundMesh.h:96
GLenum GLuint GLintptr GLsizeiptr size
Definition: gl2ext.h:629
static bool trim_top_right_cond(const vec2 &offset)
Definition: GroundMesh.cpp:330
std::vector< vec2 > level_offsets
Definition: GroundMesh.h:99
GLint GLint GLint GLint GLint x
Definition: gl2ext.h:574
void render_draw_list()
[Rendering the entire terrain]
Definition: GroundMesh.cpp:556
GLenum GLuint GLint level
Definition: gl2ext.h:385
GLenum GLuint buffer
Definition: gl2ext.h:628
#define GL_MAP_WRITE_BIT
Definition: gl2ext.h:1050
Block trim_bottom_right
Definition: GroundMesh.h:73
#define LOGE(...)
Definition: AstcTextures.h:30
precision highp float
Definition: hiz_cull.cs:37
Definition: mesh.hpp:39
bool intersects_frustum(const vec2 &offset, const vec2 &range, unsigned int level)
Definition: GroundMesh.cpp:444
Block degenerate_left
Definition: GroundMesh.h:76
GLuint vertex_buffer
Definition: GroundMesh.h:43
static T * buffer_offset(T *buffer, size_t offset)
Definition: GroundMesh.cpp:462
unsigned int instances
Definition: GroundMesh.h:94
Block degenerate_bottom
Definition: GroundMesh.h:79
size_t uniform_buffer_size
Definition: GroundMesh.h:47
DrawInfo get_draw_info_trim_full(InstanceData *instance_data)
Definition: GroundMesh.cpp:262
Block vertical
Definition: GroundMesh.h:69
DrawInfo get_draw_info_trim_bottom_right(InstanceData *instance_data)
Definition: GroundMesh.cpp:360