Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/intern
diff options
context:
space:
mode:
Diffstat (limited to 'intern')
-rw-r--r--intern/CMakeLists.txt1
-rw-r--r--intern/cycles/blender/addon/__init__.py18
-rw-r--r--intern/cycles/blender/addon/engine.py13
-rw-r--r--intern/cycles/blender/addon/properties.py6
-rw-r--r--intern/cycles/blender/addon/ui.py60
-rw-r--r--intern/cycles/blender/blender_curves.cpp8
-rw-r--r--intern/cycles/blender/blender_mesh.cpp7
-rw-r--r--intern/cycles/blender/blender_object.cpp174
-rw-r--r--intern/cycles/blender/blender_python.cpp16
-rw-r--r--intern/cycles/blender/blender_session.cpp12
-rw-r--r--intern/cycles/blender/blender_session.h4
-rw-r--r--intern/cycles/blender/blender_shader.cpp107
-rw-r--r--intern/cycles/blender/blender_sync.cpp40
-rw-r--r--intern/cycles/blender/blender_sync.h17
-rw-r--r--intern/cycles/blender/blender_texture.cpp3
-rw-r--r--intern/cycles/blender/blender_texture.h2
-rw-r--r--intern/cycles/blender/blender_util.h3
-rw-r--r--intern/cycles/device/device.cpp321
-rw-r--r--intern/cycles/device/device.h22
-rw-r--r--intern/cycles/device/device_cuda.cpp57
-rw-r--r--intern/cycles/device/device_multi.cpp9
-rw-r--r--intern/cycles/render/buffers.cpp6
-rw-r--r--intern/cycles/util/util_opengl.h8
-rw-r--r--intern/cycles/util/util_view.cpp2
-rw-r--r--intern/elbeem/intern/solver_control.cpp152
-rw-r--r--intern/elbeem/intern/solver_util.cpp217
-rw-r--r--intern/gawain/CMakeLists.txt40
-rw-r--r--intern/gawain/gawain/attrib_binding.h19
-rw-r--r--intern/gawain/gawain/attrib_binding_private.h20
-rw-r--r--intern/gawain/gawain/batch.h129
-rw-r--r--intern/gawain/gawain/buffer_id.h34
-rw-r--r--intern/gawain/gawain/common.h34
-rw-r--r--intern/gawain/gawain/element.h75
-rw-r--r--intern/gawain/gawain/imm_util.h18
-rw-r--r--intern/gawain/gawain/immediate.h119
-rw-r--r--intern/gawain/gawain/primitive.h40
-rw-r--r--intern/gawain/gawain/primitive_private.h14
-rw-r--r--intern/gawain/gawain/shader_interface.h53
-rw-r--r--intern/gawain/gawain/vertex_buffer.h108
-rw-r--r--intern/gawain/gawain/vertex_format.h78
-rw-r--r--intern/gawain/gawain/vertex_format_private.h16
-rw-r--r--intern/gawain/src/attrib_binding.c70
-rw-r--r--intern/gawain/src/batch.c449
-rw-r--r--intern/gawain/src/buffer_id.cpp115
-rw-r--r--intern/gawain/src/element.c295
-rw-r--r--intern/gawain/src/imm_util.c46
-rw-r--r--intern/gawain/src/immediate.c919
-rw-r--r--intern/gawain/src/primitive.c63
-rw-r--r--intern/gawain/src/shader_interface.c311
-rw-r--r--intern/gawain/src/vertex_buffer.c222
-rw-r--r--intern/gawain/src/vertex_format.c296
-rw-r--r--intern/ghost/intern/GHOST_Context.cpp6
-rw-r--r--intern/ghost/intern/GHOST_Context.h11
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.h13
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.mm36
-rw-r--r--intern/ghost/intern/GHOST_ContextEGL.cpp33
-rw-r--r--intern/ghost/intern/GHOST_ContextEGL.h20
-rw-r--r--intern/ghost/intern/GHOST_ContextGLX.cpp44
-rw-r--r--intern/ghost/intern/GHOST_ContextGLX.h19
-rw-r--r--intern/ghost/intern/GHOST_ContextSDL.cpp2
-rw-r--r--intern/ghost/intern/GHOST_ContextWGL.cpp161
-rw-r--r--intern/ghost/intern/GHOST_ContextWGL.h39
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm69
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp131
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp122
-rw-r--r--intern/ghost/test/CMakeLists.txt3
-rw-r--r--intern/glew-mx/glew-mx.h31
-rw-r--r--intern/glew-mx/intern/gl-deprecated.h6
-rw-r--r--intern/glew-mx/intern/glew-mx.c58
-rw-r--r--intern/itasc/FixedObject.hpp2
-rw-r--r--intern/itasc/MovingFrame.cpp4
-rw-r--r--intern/itasc/MovingFrame.hpp5
-rw-r--r--intern/itasc/Scene.cpp4
-rw-r--r--intern/itasc/Scene.hpp2
-rw-r--r--intern/itasc/UncontrolledObject.hpp5
-rw-r--r--intern/itasc/WorldObject.hpp2
-rw-r--r--intern/opencolorio/CMakeLists.txt2
-rw-r--r--intern/opencolorio/gpu_shader_display_transform.glsl10
-rw-r--r--intern/opencolorio/gpu_shader_display_transform_vertex.glsl12
-rw-r--r--intern/opencolorio/ocio_impl_glsl.cc98
-rw-r--r--intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl15
-rw-r--r--intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl7
-rw-r--r--intern/opensubdiv/opensubdiv_capi.cc13
-rw-r--r--intern/opensubdiv/opensubdiv_capi.h4
-rw-r--r--intern/opensubdiv/opensubdiv_gpu_capi.cc83
-rw-r--r--intern/opensubdiv/opensubdiv_utils_capi.cc14
86 files changed, 4503 insertions, 1451 deletions
diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt
index bfe230250ae..af3b9296077 100644
--- a/intern/CMakeLists.txt
+++ b/intern/CMakeLists.txt
@@ -33,6 +33,7 @@ add_subdirectory(opencolorio)
add_subdirectory(mikktspace)
add_subdirectory(glew-mx)
add_subdirectory(eigen)
+add_subdirectory(gawain)
if(WITH_GAMEENGINE_DECKLINK)
add_subdirectory(decklink)
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py
index a2d6262fb20..1cb7835d14d 100644
--- a/intern/cycles/blender/addon/__init__.py
+++ b/intern/cycles/blender/addon/__init__.py
@@ -19,7 +19,7 @@
bl_info = {
"name": "Cycles Render Engine",
"author": "",
- "blender": (2, 76, 0),
+ "blender": (2, 80, 0),
"location": "Info header, render engine menu",
"description": "Cycles Render Engine integration",
"warning": "",
@@ -66,21 +66,21 @@ class CyclesRender(bpy.types.RenderEngine):
engine.free(self)
# final render
- def update(self, data, scene):
+ def update(self, data, depsgraph, scene):
if not self.session:
if self.is_preview:
cscene = bpy.context.scene.cycles
use_osl = cscene.shading_system and cscene.device == 'CPU'
- engine.create(self, data, scene,
+ engine.create(self, data, depsgraph, scene,
None, None, None, use_osl)
else:
- engine.create(self, data, scene)
+ engine.create(self, data, depsgraph, scene)
else:
engine.reset(self, data, scene)
- def render(self, scene):
- engine.render(self)
+ def render_to_image(self, depsgraph):
+ engine.render(self, depsgraph)
def bake(self, scene, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result):
engine.bake(self, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result)
@@ -88,12 +88,12 @@ class CyclesRender(bpy.types.RenderEngine):
# viewport render
def view_update(self, context):
if not self.session:
- engine.create(self, context.blend_data, context.scene,
+ engine.create(self, context.blend_data, context.depsgraph, context.scene,
context.region, context.space_data, context.region_data)
engine.update(self, context.blend_data, context.scene)
- def view_draw(self, context):
- engine.draw(self, context.region, context.space_data, context.region_data)
+ def render_to_view(self, context):
+ engine.draw(self, context.depsgraph, context.region, context.space_data, context.region_data)
def update_script_node(self, node):
if engine.with_osl():
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index 3018fd5b316..5b2cb9fe39b 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -123,12 +123,13 @@ def exit():
_cycles.exit()
-def create(engine, data, scene, region=None, v3d=None, rv3d=None, preview_osl=False):
+def create(engine, data, depsgraph, scene, region=None, v3d=None, rv3d=None, preview_osl=False):
import bpy
import _cycles
data = data.as_pointer()
userpref = bpy.context.user_preferences.as_pointer()
+ depsgraph = depsgraph.as_pointer()
scene = scene.as_pointer()
if region:
region = region.as_pointer()
@@ -142,7 +143,8 @@ def create(engine, data, scene, region=None, v3d=None, rv3d=None, preview_osl=Fa
else:
_cycles.debug_flags_reset()
- engine.session = _cycles.create(engine.as_pointer(), userpref, data, scene, region, v3d, rv3d, preview_osl)
+ engine.session = _cycles.create(
+ engine.as_pointer(), userpref, data, depsgraph, scene, region, v3d, rv3d, preview_osl)
def free(engine):
@@ -153,7 +155,7 @@ def free(engine):
del engine.session
-def render(engine):
+def render(engine, depsgraph):
import _cycles
if hasattr(engine, "session"):
_cycles.render(engine.session)
@@ -178,13 +180,14 @@ def update(engine, data, scene):
_cycles.sync(engine.session)
-def draw(engine, region, v3d, rv3d):
+def draw(engine, depsgraph, region, v3d, rv3d):
import _cycles
+ depsgraph = depsgraph.as_pointer()
v3d = v3d.as_pointer()
rv3d = rv3d.as_pointer()
# draw render image
- _cycles.draw(engine.session, v3d, rv3d)
+ _cycles.draw(engine.session, depsgraph, v3d, rv3d)
def available_devices():
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index c744c1d6932..93b90ec650b 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -195,12 +195,6 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
description="Pause all viewport preview renders",
default=False,
)
- cls.preview_active_layer = BoolProperty(
- name="Preview Active Layer",
- description="Preview active render layer in viewport",
- default=False,
- )
-
cls.aa_samples = IntProperty(
name="AA Samples",
description="Number of antialiasing samples to render for each pixel",
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index b9565aa4c7f..983f817539b 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -17,6 +17,7 @@
# <pep8 compliant>
import bpy
+from bpy_extras.node_utils import find_node_input, find_output_node
from bpy.types import (
Panel,
@@ -895,43 +896,22 @@ class CYCLES_OT_use_shading_nodes(Operator):
return {'FINISHED'}
-def find_node(material, nodetype):
- if material and material.node_tree:
- ntree = material.node_tree
-
- active_output_node = None
- for node in ntree.nodes:
- if getattr(node, "type", None) == nodetype:
- if getattr(node, "is_active_output", True):
- return node
- if not active_output_node:
- active_output_node = node
- return active_output_node
-
- return None
-
-
-def find_node_input(node, name):
- for input in node.inputs:
- if input.name == name:
- return input
-
- return None
-
-
-def panel_node_draw(layout, id_data, output_type, input_name):
+def panel_node_draw(layout, id_data, output_types, input_name):
if not id_data.use_nodes:
layout.operator("cycles.use_shading_nodes", icon='NODETREE')
return False
ntree = id_data.node_tree
- node = find_node(id_data, output_type)
- if not node:
- layout.label(text="No output node")
- else:
+ node = find_output_node(ntree, output_types)
+ if node:
input = find_node_input(node, input_name)
- layout.template_node_view(ntree, node, input)
+ if input:
+ layout.template_node_view(ntree, node, input)
+ else:
+ layout.label(text="Incompatible output node")
+ else:
+ layout.label(text="No output node")
return True
@@ -1020,7 +1000,7 @@ class CyclesLamp_PT_nodes(CyclesButtonsPanel, Panel):
layout = self.layout
lamp = context.lamp
- if not panel_node_draw(layout, lamp, 'OUTPUT_LAMP', 'Surface'):
+ if not panel_node_draw(layout, lamp, ('OUTPUT_LAMP',), 'Surface'):
layout.prop(lamp, "color")
@@ -1075,7 +1055,7 @@ class CyclesWorld_PT_surface(CyclesButtonsPanel, Panel):
world = context.world
- if not panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Surface'):
+ if not panel_node_draw(layout, world, ('OUTPUT_WORLD',), 'Surface'):
layout.prop(world, "horizon_color", text="Color")
@@ -1093,7 +1073,7 @@ class CyclesWorld_PT_volume(CyclesButtonsPanel, Panel):
layout = self.layout
world = context.world
- panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume')
+ panel_node_draw(layout, world, ('OUTPUT_WORLD',), 'Volume')
class CyclesWorld_PT_ambient_occlusion(CyclesButtonsPanel, Panel):
@@ -1238,7 +1218,7 @@ class CyclesMaterial_PT_surface(CyclesButtonsPanel, Panel):
layout = self.layout
mat = context.material
- if not panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Surface'):
+ if not panel_node_draw(layout, mat, ('OUTPUT_MATERIAL', 'OUTPUT_EEVEE_MATERIAL'), 'Surface'):
layout.prop(mat, "diffuse_color")
@@ -1258,7 +1238,7 @@ class CyclesMaterial_PT_volume(CyclesButtonsPanel, Panel):
mat = context.material
# cmat = mat.cycles
- panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Volume')
+ panel_node_draw(layout, mat, ('OUTPUT_MATERIAL', 'OUTPUT_EEVEE_MATERIAL'), 'Volume')
class CyclesMaterial_PT_displacement(CyclesButtonsPanel, Panel):
@@ -1274,7 +1254,7 @@ class CyclesMaterial_PT_displacement(CyclesButtonsPanel, Panel):
layout = self.layout
mat = context.material
- panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement')
+ panel_node_draw(layout, mat, ('OUTPUT_MATERIAL', 'OUTPUT_EEVEE_MATERIAL'), 'Displacement')
class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
@@ -1663,6 +1643,7 @@ class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel):
row.prop(rd, "simplify_subdivision", text="Viewport")
row.prop(rd, "simplify_subdivision_render", text="Render")
+
col = layout.column(align=True)
col.label(text="Child Particles")
row = col.row(align=True)
@@ -1725,11 +1706,8 @@ def draw_pause(self, context):
if scene.render.engine == "CYCLES":
view = context.space_data
- if view.viewport_shade == 'RENDERED':
- cscene = scene.cycles
- layername = scene.render.layers.active.name
- layout.prop(cscene, "preview_pause", icon="PAUSE", text="")
- layout.prop(cscene, "preview_active_layer", icon="RENDERLAYERS", text=layername)
+ cscene = scene.cycles
+ layout.prop(cscene, "preview_pause", icon="PAUSE", text="")
def get_panels():
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp
index 42b985305ea..63b07936426 100644
--- a/intern/cycles/blender/blender_curves.cpp
+++ b/intern/cycles/blender/blender_curves.cpp
@@ -325,14 +325,14 @@ static bool ObtainCacheParticleVcol(Mesh *mesh,
return true;
}
-static void set_resolution(BL::Object *b_ob, BL::Scene *scene, bool render)
+static void set_resolution(BL::Object *b_ob, BL::Scene *scene, BL::SceneLayer *sl, bool render)
{
BL::Object::modifiers_iterator b_mod;
for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && ((b_mod->show_viewport()) || (b_mod->show_render()))) {
BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
- b_psys.set_resolution(*scene, *b_ob, (render)? 2: 1);
+ b_psys.set_resolution(*scene, *sl, *b_ob, (render)? 2: 1);
}
}
}
@@ -912,7 +912,7 @@ void BlenderSync::sync_curves(Mesh *mesh,
ParticleCurveData CData;
if(!preview)
- set_resolution(&b_ob, &b_scene, true);
+ set_resolution(&b_ob, &b_scene, &b_scene_layer, true);
ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, !preview);
@@ -1057,7 +1057,7 @@ void BlenderSync::sync_curves(Mesh *mesh,
}
if(!preview)
- set_resolution(&b_ob, &b_scene, false);
+ set_resolution(&b_ob, &b_scene, &b_scene_layer, false);
mesh->compute_bounds();
}
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index b4cca5f00f4..2e3271c735f 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -414,7 +414,7 @@ static void attr_create_uv_map(Scene *scene,
int i = 0;
for(b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, ++i) {
- bool active_render = b_mesh.uv_textures[i].active_render();
+ bool active_render = b_mesh.uv_layers[i].active_render();
AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
ustring name = ustring(l->name().c_str());
@@ -942,6 +942,7 @@ static void sync_mesh_fluid_motion(BL::Object& b_ob, Scene *scene, Mesh *mesh)
}
Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
+ BL::Object& b_ob_instance,
bool object_updated,
bool hide_tris)
{
@@ -955,7 +956,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
/* test if we can instance or if the object is modified */
BL::ID b_ob_data = b_ob.data();
- BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data;
+ BL::ID key = (BKE_object_is_modified(b_ob))? b_ob_instance: b_ob_data;
BL::Material material_override = render_layer.material_override;
/* find shader indices */
@@ -1052,6 +1053,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
BL::Mesh b_mesh = object_to_mesh(b_data,
b_ob,
b_scene,
+ b_scene_layer,
true,
!preview,
need_undeformed,
@@ -1183,6 +1185,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
b_mesh = object_to_mesh(b_data,
b_ob,
b_scene,
+ b_scene_layer,
true,
!preview,
false,
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index a930c439370..991b834dcfa 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -94,12 +94,13 @@ static uint object_ray_visibility(BL::Object& b_ob)
void BlenderSync::sync_light(BL::Object& b_parent,
int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
BL::Object& b_ob,
+ BL::Object& b_ob_instance,
Transform& tfm,
bool *use_portal)
{
/* test if we need to sync */
Light *light;
- ObjectKey key(b_parent, persistent_id, b_ob);
+ ObjectKey key(b_parent, persistent_id, b_ob_instance);
if(!light_map.sync(&light, b_ob, b_parent, key)) {
if(light->is_portal)
@@ -236,24 +237,41 @@ void BlenderSync::sync_background_light(bool use_portal)
/* Object */
-Object *BlenderSync::sync_object(BL::Object& b_parent,
- int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
- BL::DupliObject& b_dupli_ob,
- Transform& tfm,
+Object *BlenderSync::sync_object(BL::Depsgraph::duplis_iterator& b_dupli_iter,
uint layer_flag,
float motion_time,
bool hide_tris,
BlenderObjectCulling& culling,
bool *use_portal)
{
- BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
- bool motion = motion_time != 0.0f;
-
+ const bool is_instance = b_dupli_iter->is_instance();
+ BL::Object b_ob = b_dupli_iter->object();
+ BL::Object b_parent = is_instance ? b_dupli_iter->parent()
+ : b_dupli_iter->object();
+ BL::Object b_ob_instance = is_instance ? b_dupli_iter->instance_object()
+ : b_ob;
+ const bool motion = motion_time != 0.0f;
+ /*const*/ Transform tfm = get_transform(b_ob.matrix_world());
+ int *persistent_id = NULL;
+ BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id_array;
+ if(is_instance) {
+ persistent_id_array = b_dupli_iter->persistent_id();
+ persistent_id = persistent_id_array.data;
+ }
+
/* light is handled separately */
if(object_is_light(b_ob)) {
/* don't use lamps for excluded layers used as mask layer */
- if(!motion && !((layer_flag & render_layer.holdout_layer) && (layer_flag & render_layer.exclude_layer)))
- sync_light(b_parent, persistent_id, b_ob, tfm, use_portal);
+ if(!motion && !((layer_flag & render_layer.holdout_layer) &&
+ (layer_flag & render_layer.exclude_layer)))
+ {
+ sync_light(b_parent,
+ persistent_id,
+ b_ob,
+ b_ob_instance,
+ tfm,
+ use_portal);
+ }
return NULL;
}
@@ -269,7 +287,7 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
}
/* key to lookup object */
- ObjectKey key(b_parent, persistent_id, b_ob);
+ ObjectKey key(b_parent, persistent_id, b_ob_instance);
Object *object;
/* motion vector case */
@@ -311,7 +329,7 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0;
/* mesh sync */
- object->mesh = sync_mesh(b_ob, object_updated, hide_tris);
+ object->mesh = sync_mesh(b_ob, b_ob_instance, object_updated, hide_tris);
/* special case not tracked by object update flags */
@@ -380,10 +398,10 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
}
/* dupli texture coordinates and random_id */
- if(b_dupli_ob) {
- object->dupli_generated = 0.5f*get_float3(b_dupli_ob.orco()) - make_float3(0.5f, 0.5f, 0.5f);
- object->dupli_uv = get_float2(b_dupli_ob.uv());
- object->random_id = b_dupli_ob.random_id();
+ if(is_instance) {
+ object->dupli_generated = 0.5f*get_float3(b_dupli_iter->orco()) - make_float3(0.5f, 0.5f, 0.5f);
+ object->dupli_uv = get_float2(b_dupli_iter->uv());
+ object->random_id = b_dupli_iter->random_id();
}
else {
object->dupli_generated = make_float3(0.0f, 0.0f, 0.0f);
@@ -469,19 +487,11 @@ static bool object_render_hide(BL::Object& b_ob,
}
}
-static bool object_render_hide_duplis(BL::Object& b_ob)
-{
- BL::Object parent = b_ob.parent();
-
- return (parent && object_render_hide_original(b_ob.type(), parent.dupli_type()));
-}
-
/* Object Loop */
void BlenderSync::sync_objects(float motion_time)
{
/* layer data */
- uint scene_layer = render_layer.scene_layer;
bool motion = motion_time != 0.0f;
if(!motion) {
@@ -500,100 +510,34 @@ void BlenderSync::sync_objects(float motion_time)
BlenderObjectCulling culling(scene, b_scene);
/* object loop */
- BL::Scene::object_bases_iterator b_base;
- BL::Scene b_sce = b_scene;
- /* modifier result type (not exposed as enum in C++ API)
- * 1 : DAG_EVAL_PREVIEW
- * 2 : DAG_EVAL_RENDER
- */
- int dupli_settings = (render_layer.use_viewport_visibility) ? 1 : 2;
-
bool cancel = false;
bool use_portal = false;
- uint layer_override = get_layer(b_engine.layer_override());
- for(; b_sce && !cancel; b_sce = b_sce.background_set()) {
- /* Render layer's scene_layer is affected by local view already,
- * which is not a desired behavior here.
- */
- uint scene_layers = layer_override ? layer_override : get_layer(b_scene.layers());
- for(b_sce.object_bases.begin(b_base); b_base != b_sce.object_bases.end() && !cancel; ++b_base) {
- BL::Object b_ob = b_base->object();
- bool hide = (render_layer.use_viewport_visibility)? b_ob.hide(): b_ob.hide_render();
- uint ob_layer = get_layer(b_base->layers(),
- b_base->layers_local_view(),
- object_is_light(b_ob),
- scene_layers);
- hide = hide || !(ob_layer & scene_layer);
-
- if(!hide) {
- progress.set_sync_status("Synchronizing object", b_ob.name());
-
- /* load per-object culling data */
- culling.init_object(scene, b_ob);
-
- if(b_ob.is_duplicator() && !object_render_hide_duplis(b_ob)) {
- /* dupli objects */
- b_ob.dupli_list_create(b_scene, dupli_settings);
-
- BL::Object::dupli_list_iterator b_dup;
-
- for(b_ob.dupli_list.begin(b_dup); b_dup != b_ob.dupli_list.end(); ++b_dup) {
- Transform tfm = get_transform(b_dup->matrix());
- BL::Object b_dup_ob = b_dup->object();
- bool dup_hide = (render_layer.use_viewport_visibility)? b_dup_ob.hide(): b_dup_ob.hide_render();
- bool in_dupli_group = (b_dup->type() == BL::DupliObject::type_GROUP);
- bool hide_tris;
-
- if(!(b_dup->hide() || dup_hide || object_render_hide(b_dup_ob, false, in_dupli_group, hide_tris))) {
- /* the persistent_id allows us to match dupli objects
- * between frames and updates */
- BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup->persistent_id();
-
- /* sync object and mesh or light data */
- Object *object = sync_object(b_ob,
- persistent_id.data,
- *b_dup,
- tfm,
- ob_layer,
- motion_time,
- hide_tris,
- culling,
- &use_portal);
-
- /* sync possible particle data, note particle_id
- * starts counting at 1, first is dummy particle */
- if(!motion && object) {
- sync_dupli_particle(b_ob, *b_dup, object);
- }
-
- }
- }
-
- b_ob.dupli_list_clear();
- }
-
- /* test if object needs to be hidden */
- bool hide_tris;
-
- if(!object_render_hide(b_ob, true, true, hide_tris)) {
- /* object itself */
- Transform tfm = get_transform(b_ob.matrix_world());
- BL::DupliObject b_empty_dupli_ob(PointerRNA_NULL);
- sync_object(b_ob,
- NULL,
- b_empty_dupli_ob,
- tfm,
- ob_layer,
- motion_time,
- hide_tris,
- culling,
- &use_portal);
- }
- }
-
- cancel = progress.get_cancel();
- }
+ BL::Depsgraph::duplis_iterator b_dupli_iter;
+ for(b_depsgraph.duplis.begin(b_dupli_iter);
+ b_dupli_iter != b_depsgraph.duplis.end() && !cancel;
+ ++b_dupli_iter)
+ {
+ BL::Object b_ob = b_dupli_iter->object();
+ progress.set_sync_status("Synchronizing object", b_ob.name());
+
+ /* load per-object culling data */
+ culling.init_object(scene, b_ob);
+
+ /* test if object needs to be hidden */
+ bool hide_tris;
+
+ if(!object_render_hide(b_ob, true, true, hide_tris)) {
+ /* object itself */
+ sync_object(b_dupli_iter,
+ ~(0), /* until we get rid of layers */
+ motion_time,
+ hide_tris,
+ culling,
+ &use_portal);
+ }
+
+ cancel = progress.get_cancel();
}
progress.set_sync_status("");
diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp
index 54973fd1b7f..772ce1d555e 100644
--- a/intern/cycles/blender/blender_python.cpp
+++ b/intern/cycles/blender/blender_python.cpp
@@ -200,10 +200,10 @@ static PyObject *exit_func(PyObject * /*self*/, PyObject * /*args*/)
static PyObject *create_func(PyObject * /*self*/, PyObject *args)
{
- PyObject *pyengine, *pyuserpref, *pydata, *pyscene, *pyregion, *pyv3d, *pyrv3d;
+ PyObject *pyengine, *pyuserpref, *pydata, *pygraph, *pyscene, *pyregion, *pyv3d, *pyrv3d;
int preview_osl;
- if(!PyArg_ParseTuple(args, "OOOOOOOi", &pyengine, &pyuserpref, &pydata, &pyscene,
+ if(!PyArg_ParseTuple(args, "OOOOOOOOi", &pyengine, &pyuserpref, &pydata, &pygraph, &pyscene,
&pyregion, &pyv3d, &pyrv3d, &preview_osl))
{
return NULL;
@@ -222,6 +222,10 @@ static PyObject *create_func(PyObject * /*self*/, PyObject *args)
RNA_main_pointer_create((Main*)PyLong_AsVoidPtr(pydata), &dataptr);
BL::BlendData data(dataptr);
+ PointerRNA graphptr;
+ RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pygraph), &graphptr);
+ BL::Depsgraph graph(graphptr);
+
PointerRNA sceneptr;
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
BL::Scene scene(sceneptr);
@@ -246,7 +250,7 @@ static PyObject *create_func(PyObject * /*self*/, PyObject *args)
int width = region.width();
int height = region.height();
- session = new BlenderSession(engine, userpref, data, scene, v3d, rv3d, width, height);
+ session = new BlenderSession(engine, userpref, data, graph, scene, v3d, rv3d, width, height);
}
else {
/* override some settings for preview */
@@ -258,7 +262,7 @@ static PyObject *create_func(PyObject * /*self*/, PyObject *args)
}
/* offline session or preview render */
- session = new BlenderSession(engine, userpref, data, scene);
+ session = new BlenderSession(engine, userpref, data, graph, scene);
}
python_thread_state_save(&session->python_thread_state);
@@ -324,9 +328,9 @@ static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
static PyObject *draw_func(PyObject * /*self*/, PyObject *args)
{
- PyObject *pysession, *pyv3d, *pyrv3d;
+ PyObject *pysession, *pygraph, *pyv3d, *pyrv3d;
- if(!PyArg_ParseTuple(args, "OOO", &pysession, &pyv3d, &pyrv3d))
+ if(!PyArg_ParseTuple(args, "OOOO", &pysession, &pygraph, &pyv3d, &pyrv3d))
return NULL;
BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index 12de3da063f..f4e9da43454 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -52,12 +52,15 @@ int BlenderSession::end_resumable_chunk = 0;
BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
BL::UserPreferences& b_userpref,
BL::BlendData& b_data,
+ BL::Depsgraph& b_depsgraph,
BL::Scene& b_scene)
: b_engine(b_engine),
b_userpref(b_userpref),
b_data(b_data),
b_render(b_engine.render()),
+ b_depsgraph(b_depsgraph),
b_scene(b_scene),
+ b_scene_layer(b_engine.scene_layer()),
b_v3d(PointerRNA_NULL),
b_rv3d(PointerRNA_NULL),
python_thread_state(NULL)
@@ -76,6 +79,7 @@ BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
BL::UserPreferences& b_userpref,
BL::BlendData& b_data,
+ BL::Depsgraph& b_depsgraph,
BL::Scene& b_scene,
BL::SpaceView3D& b_v3d,
BL::RegionView3D& b_rv3d,
@@ -84,7 +88,9 @@ BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
b_userpref(b_userpref),
b_data(b_data),
b_render(b_scene.render()),
+ b_depsgraph(b_depsgraph),
b_scene(b_scene),
+ b_scene_layer(b_engine.scene_layer()),
b_v3d(b_v3d),
b_rv3d(b_rv3d),
width(width),
@@ -141,7 +147,7 @@ void BlenderSession::create_session()
session->set_pause(session_pause);
/* create sync */
- sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress, is_cpu);
+ sync = new BlenderSync(b_engine, b_data, b_depsgraph, b_scene, scene, !background, session->progress, is_cpu);
BL::Object b_camera_override(b_engine.camera_override());
if(b_v3d) {
if(session_pause == false) {
@@ -211,7 +217,7 @@ void BlenderSession::reset_session(BL::BlendData& b_data_, BL::Scene& b_scene_)
session->stats.mem_peak = session->stats.mem_used;
/* sync object should be re-created */
- sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress, is_cpu);
+ sync = new BlenderSync(b_engine, b_data, b_depsgraph, b_scene, scene, !background, session->progress, is_cpu);
/* for final render we will do full data sync per render layer, only
* do some basic syncing here, no objects or materials for speed */
@@ -1297,7 +1303,7 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
int length;
int settings = background ? 1 : 0; /* 1 - render settings, 0 - vewport settings. */
- b_point_density_node.calc_point_density(b_scene, settings, &length, &pixels);
+ b_point_density_node.calc_point_density(b_scene, b_scene_layer, settings, &length, &pixels);
}
}
diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h
index cbd2303d282..7ae7bde1737 100644
--- a/intern/cycles/blender/blender_session.h
+++ b/intern/cycles/blender/blender_session.h
@@ -36,11 +36,13 @@ public:
BlenderSession(BL::RenderEngine& b_engine,
BL::UserPreferences& b_userpref,
BL::BlendData& b_data,
+ BL::Depsgraph& b_depsgraph,
BL::Scene& b_scene);
BlenderSession(BL::RenderEngine& b_engine,
BL::UserPreferences& b_userpref,
BL::BlendData& b_data,
+ BL::Depsgraph& b_depsgraph,
BL::Scene& b_scene,
BL::SpaceView3D& b_v3d,
BL::RegionView3D& b_rv3d,
@@ -104,7 +106,9 @@ public:
BL::UserPreferences b_userpref;
BL::BlendData b_data;
BL::RenderSettings b_render;
+ BL::Depsgraph b_depsgraph;
BL::Scene b_scene;
+ BL::SceneLayer b_scene_layer;
BL::SpaceView3D b_v3d;
BL::RegionView3D b_rv3d;
string b_rlay_name;
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index bdbab1006c0..bbf7dc720a8 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -231,17 +231,11 @@ static void get_tex_mapping(TextureMapping *mapping,
mapping->max = get_float3(b_mapping.max());
}
-static bool is_output_node(BL::Node& b_node)
-{
- return (b_node.is_a(&RNA_ShaderNodeOutputMaterial)
- || b_node.is_a(&RNA_ShaderNodeOutputWorld)
- || b_node.is_a(&RNA_ShaderNodeOutputLamp));
-}
-
static ShaderNode *add_node(Scene *scene,
BL::RenderEngine& b_engine,
BL::BlendData& b_data,
BL::Scene& b_scene,
+ BL::SceneLayer b_scene_layer,
const bool background,
ShaderGraph *graph,
BL::ShaderNodeTree& b_ntree,
@@ -838,7 +832,7 @@ static ShaderNode *add_node(Scene *scene,
/* TODO(sergey): Use more proper update flag. */
if(true) {
- b_point_density_node.cache_point_density(b_scene, settings);
+ b_point_density_node.cache_point_density(b_scene, b_scene_layer, settings);
scene->image_manager->tag_reload_image(
point_density->filename.string(),
point_density->builtin_data,
@@ -856,7 +850,7 @@ static ShaderNode *add_node(Scene *scene,
BL::Object b_ob(b_point_density_node.object());
if(b_ob) {
float3 loc, size;
- point_density_texture_space(b_scene,
+ point_density_texture_space(b_scene, b_scene_layer,
b_point_density_node,
settings,
loc,
@@ -949,10 +943,47 @@ static ShaderOutput *node_find_output_by_name(ShaderNode *node,
return node->output(name.c_str());
}
+static BL::ShaderNode find_output_node(BL::ShaderNodeTree& b_ntree)
+{
+ BL::ShaderNodeTree::nodes_iterator b_node;
+ BL::ShaderNode output_node(PointerRNA_NULL);
+ BL::ShaderNode eevee_output_node(PointerRNA_NULL);
+
+ for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
+ BL::ShaderNodeOutputMaterial b_output_node(*b_node);
+
+ if (b_output_node.is_a(&RNA_ShaderNodeOutputMaterial) ||
+ b_output_node.is_a(&RNA_ShaderNodeOutputWorld) ||
+ b_output_node.is_a(&RNA_ShaderNodeOutputLamp)) {
+ /* regular Cycles output node */
+ if(b_output_node.is_active_output()) {
+ output_node = b_output_node;
+ break;
+ }
+ else if(!output_node.ptr.data) {
+ output_node = b_output_node;
+ }
+ }
+ else if (b_output_node.is_a(&RNA_ShaderNodeOutputEeveeMaterial)) {
+ /* Eevee output used if no Cycles node exists */
+ if(b_output_node.is_active_output()) {
+ eevee_output_node = b_output_node;
+ }
+ else if(!eevee_output_node.ptr.data) {
+ eevee_output_node = b_output_node;
+ }
+
+ }
+ }
+
+ return (output_node.ptr.data) ? output_node : eevee_output_node;
+}
+
static void add_nodes(Scene *scene,
BL::RenderEngine& b_engine,
BL::BlendData& b_data,
BL::Scene& b_scene,
+ BL::SceneLayer& b_scene_layer,
const bool background,
ShaderGraph *graph,
BL::ShaderNodeTree& b_ntree,
@@ -968,23 +999,7 @@ static void add_nodes(Scene *scene,
BL::Node::outputs_iterator b_output;
/* find the node to use for output if there are multiple */
- bool found_active_output = false;
- BL::ShaderNode output_node(PointerRNA_NULL);
-
- for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
- if(is_output_node(*b_node)) {
- BL::ShaderNodeOutputMaterial b_output_node(*b_node);
-
- if(b_output_node.is_active_output()) {
- output_node = b_output_node;
- found_active_output = true;
- break;
- }
- else if(!output_node.ptr.data && !found_active_output) {
- output_node = b_output_node;
- }
- }
- }
+ BL::ShaderNode output_node = find_output_node(b_ntree);
/* add nodes */
for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
@@ -1043,6 +1058,7 @@ static void add_nodes(Scene *scene,
b_engine,
b_data,
b_scene,
+ b_scene_layer,
background,
graph,
b_group_ntree,
@@ -1081,10 +1097,8 @@ static void add_nodes(Scene *scene,
else {
ShaderNode *node = NULL;
- if(is_output_node(*b_node)) {
- if(b_node->ptr.data == output_node.ptr.data) {
- node = graph->output();
- }
+ if(b_node->ptr.data == output_node.ptr.data) {
+ node = graph->output();
}
else {
BL::ShaderNode b_shader_node(*b_node);
@@ -1092,6 +1106,7 @@ static void add_nodes(Scene *scene,
b_engine,
b_data,
b_scene,
+ b_scene_layer,
background,
graph,
b_ntree,
@@ -1155,6 +1170,7 @@ static void add_nodes(Scene *scene,
BL::RenderEngine& b_engine,
BL::BlendData& b_data,
BL::Scene& b_scene,
+ BL::SceneLayer& b_scene_layer,
const bool background,
ShaderGraph *graph,
BL::ShaderNodeTree& b_ntree)
@@ -1164,6 +1180,7 @@ static void add_nodes(Scene *scene,
b_engine,
b_data,
b_scene,
+ b_scene_layer,
background,
graph,
b_ntree,
@@ -1177,13 +1194,18 @@ void BlenderSync::sync_materials(bool update_all)
{
shader_map.set_default(scene->default_surface);
- /* material loop */
- BL::BlendData::materials_iterator b_mat;
-
TaskPool pool;
set<Shader*> updated_shaders;
- for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat) {
+ /* material loop */
+ BL::BlendData::materials_iterator b_mat_orig;
+ for(b_data.materials.begin(b_mat_orig);
+ b_mat_orig != b_data.materials.end();
+ ++b_mat_orig)
+ {
+ /* TODO(sergey): Iterate over evaluated data rather than using mapping. */
+ BL::Material b_mat_(b_depsgraph.evaluated_id_get(*b_mat_orig));
+ BL::Material *b_mat = &b_mat_;
Shader *shader;
/* test if we need to sync */
@@ -1197,7 +1219,7 @@ void BlenderSync::sync_materials(bool update_all)
if(b_mat->use_nodes() && b_mat->node_tree()) {
BL::ShaderNodeTree b_ntree(b_mat->node_tree());
- add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree);
+ add_nodes(scene, b_engine, b_data, b_scene, b_scene_layer, !preview, graph, b_ntree);
}
else {
DiffuseBsdfNode *diffuse = new DiffuseBsdfNode();
@@ -1268,7 +1290,7 @@ void BlenderSync::sync_world(bool update_all)
if(b_world && b_world.use_nodes() && b_world.node_tree()) {
BL::ShaderNodeTree b_ntree(b_world.node_tree());
- add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree);
+ add_nodes(scene, b_engine, b_data, b_scene, b_scene_layer, !preview, graph, b_ntree);
/* volume */
PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
@@ -1343,9 +1365,14 @@ void BlenderSync::sync_lamps(bool update_all)
shader_map.set_default(scene->default_light);
/* lamp loop */
- BL::BlendData::lamps_iterator b_lamp;
-
- for(b_data.lamps.begin(b_lamp); b_lamp != b_data.lamps.end(); ++b_lamp) {
+ BL::BlendData::lamps_iterator b_lamp_orig;
+ for(b_data.lamps.begin(b_lamp_orig);
+ b_lamp_orig != b_data.lamps.end();
+ ++b_lamp_orig)
+ {
+ /* TODO(sergey): Iterate over evaluated data rather than using mapping. */
+ BL::Lamp b_lamp_(b_depsgraph.evaluated_id_get(*b_lamp_orig));
+ BL::Lamp *b_lamp = &b_lamp_;
Shader *shader;
/* test if we need to sync */
@@ -1358,7 +1385,7 @@ void BlenderSync::sync_lamps(bool update_all)
BL::ShaderNodeTree b_ntree(b_lamp->node_tree());
- add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree);
+ add_nodes(scene, b_engine, b_data, b_scene, b_scene_layer, !preview, graph, b_ntree);
}
else {
float strength = 1.0f;
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index e953c685b56..adbabaccdc1 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -44,6 +44,7 @@ CCL_NAMESPACE_BEGIN
BlenderSync::BlenderSync(BL::RenderEngine& b_engine,
BL::BlendData& b_data,
+ BL::Depsgraph& b_depsgraph,
BL::Scene& b_scene,
Scene *scene,
bool preview,
@@ -51,7 +52,9 @@ BlenderSync::BlenderSync(BL::RenderEngine& b_engine,
bool is_cpu)
: b_engine(b_engine),
b_data(b_data),
+ b_depsgraph(b_depsgraph),
b_scene(b_scene),
+ b_scene_layer(b_engine.scene_layer()),
shader_map(&scene->shaders),
object_map(&scene->objects),
mesh_map(&scene->meshes),
@@ -382,26 +385,9 @@ void BlenderSync::sync_render_layers(BL::SpaceView3D& b_v3d, const char *layer)
/* 3d view */
if(b_v3d) {
- if(RNA_boolean_get(&cscene, "preview_active_layer")) {
- BL::RenderLayers layers(b_scene.render().ptr);
- layername = layers.active().name();
- layer = layername.c_str();
- }
- else {
- render_layer.scene_layer = get_layer(b_v3d.layers(), b_v3d.layers_local_view());
- render_layer.layer = render_layer.scene_layer;
- render_layer.exclude_layer = 0;
- render_layer.holdout_layer = 0;
- render_layer.material_override = PointerRNA_NULL;
- render_layer.use_background_shader = true;
- render_layer.use_background_ao = true;
- render_layer.use_hair = true;
- render_layer.use_surfaces = true;
- render_layer.use_viewport_visibility = true;
- render_layer.samples = 0;
- render_layer.bound_samples = false;
- return;
- }
+ BL::RenderLayers layers(b_scene.render().ptr);
+ layername = layers.active().name();
+ layer = layername.c_str();
}
/* render layer */
@@ -430,7 +416,6 @@ void BlenderSync::sync_render_layers(BL::SpaceView3D& b_v3d, const char *layer)
render_layer.use_background_ao = b_rlay->use_ao();
render_layer.use_surfaces = b_rlay->use_solid();
render_layer.use_hair = b_rlay->use_strand();
- render_layer.use_viewport_visibility = false;
render_layer.bound_samples = (use_layer_samples == 1);
if(use_layer_samples != 2) {
@@ -840,17 +825,8 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine,
params.shadingsystem = SHADINGSYSTEM_OSL;
/* color managagement */
-#ifdef GLEW_MX
- /* When using GLEW MX we need to check whether we've got an OpenGL
- * context for current window. This is because command line rendering
- * doesn't have OpenGL context actually.
- */
- if(glewGetContext() != NULL)
-#endif
- {
- params.display_buffer_linear = GLEW_ARB_half_float_pixel &&
- b_engine.support_display_space_shader(b_scene);
- }
+ params.display_buffer_linear = GLEW_ARB_half_float_pixel &&
+ b_engine.support_display_space_shader(b_scene);
if(b_engine.is_preview()) {
/* For preview rendering we're using same timeout as
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
index 4ec46424b5a..69fee9551dd 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -43,6 +43,7 @@ class Mesh;
class Object;
class ParticleSystem;
class Scene;
+class SceneLayer;
class Shader;
class ShaderGraph;
class ShaderNode;
@@ -51,6 +52,7 @@ class BlenderSync {
public:
BlenderSync(BL::RenderEngine& b_engine,
BL::BlendData& b_data,
+ BL::Depsgraph& b_graph,
BL::Scene& b_scene,
Scene *scene,
bool preview,
@@ -115,16 +117,16 @@ private:
void sync_curve_settings();
void sync_nodes(Shader *shader, BL::ShaderNodeTree& b_ntree);
- Mesh *sync_mesh(BL::Object& b_ob, bool object_updated, bool hide_tris);
+ Mesh *sync_mesh(BL::Object& b_ob,
+ BL::Object& b_ob_instance,
+ bool object_updated,
+ bool hide_tris);
void sync_curves(Mesh *mesh,
BL::Mesh& b_mesh,
BL::Object& b_ob,
bool motion,
int time_index = 0);
- Object *sync_object(BL::Object& b_parent,
- int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
- BL::DupliObject& b_dupli_ob,
- Transform& tfm,
+ Object *sync_object(BL::Depsgraph::duplis_iterator& b_dupli_iter,
uint layer_flag,
float motion_time,
bool hide_tris,
@@ -133,6 +135,7 @@ private:
void sync_light(BL::Object& b_parent,
int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
BL::Object& b_ob,
+ BL::Object& b_ob_instance,
Transform& tfm,
bool *use_portal);
void sync_background_light(bool use_portal);
@@ -161,7 +164,9 @@ private:
/* variables */
BL::RenderEngine b_engine;
BL::BlendData b_data;
+ BL::Depsgraph b_depsgraph;
BL::Scene b_scene;
+ BL::SceneLayer b_scene_layer;
id_map<void*, Shader> shader_map;
id_map<ObjectKey, Object> object_map;
@@ -191,7 +196,6 @@ private:
use_background_ao(true),
use_surfaces(true),
use_hair(true),
- use_viewport_visibility(false),
samples(0), bound_samples(false)
{}
@@ -205,7 +209,6 @@ private:
bool use_background_ao;
bool use_surfaces;
bool use_hair;
- bool use_viewport_visibility;
int samples;
bool bound_samples;
} render_layer;
diff --git a/intern/cycles/blender/blender_texture.cpp b/intern/cycles/blender/blender_texture.cpp
index b2e27b76189..dd08be3ddc9 100644
--- a/intern/cycles/blender/blender_texture.cpp
+++ b/intern/cycles/blender/blender_texture.cpp
@@ -34,7 +34,7 @@ void density_texture_space_invert(float3& loc,
} /* namespace */
-void point_density_texture_space(BL::Scene& b_scene,
+void point_density_texture_space(BL::Scene& b_scene, BL::SceneLayer& b_scene_layer,
BL::ShaderNodeTexPointDensity& b_point_density_node,
int settings,
float3& loc,
@@ -48,6 +48,7 @@ void point_density_texture_space(BL::Scene& b_scene,
}
float3 min, max;
b_point_density_node.calc_point_density_minmax(b_scene,
+ b_scene_layer,
settings,
&min[0],
&max[0]);
diff --git a/intern/cycles/blender/blender_texture.h b/intern/cycles/blender/blender_texture.h
index 734231a85ec..c343d5dab92 100644
--- a/intern/cycles/blender/blender_texture.h
+++ b/intern/cycles/blender/blender_texture.h
@@ -22,7 +22,7 @@
CCL_NAMESPACE_BEGIN
-void point_density_texture_space(BL::Scene& b_scene,
+void point_density_texture_space(BL::Scene& b_scene, BL::SceneLayer& b_scene_layer,
BL::ShaderNodeTexPointDensity& b_point_density_node,
const int settings,
float3& loc,
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index 363e19f7a20..314bcaf23c4 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -46,6 +46,7 @@ void python_thread_state_restore(void **python_thread_state);
static inline BL::Mesh object_to_mesh(BL::BlendData& data,
BL::Object& object,
BL::Scene& scene,
+ BL::SceneLayer scene_layer,
bool apply_modifiers,
bool render,
bool calc_undeformed,
@@ -64,7 +65,7 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data,
subsurf_mod.show_viewport(false);
}
- BL::Mesh me = data.meshes.new_from_object(scene, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed);
+ BL::Mesh me = data.meshes.new_from_object(scene, scene_layer, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed);
if(subdivision_type != Mesh::SUBDIVISION_NONE) {
BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1];
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp
index f64436aec7b..5ae83b56fcd 100644
--- a/intern/cycles/device/device.cpp
+++ b/intern/cycles/device/device.cpp
@@ -23,6 +23,7 @@
#include "util/util_debug.h"
#include "util/util_foreach.h"
#include "util/util_half.h"
+#include "util/util_logging.h"
#include "util/util_math.h"
#include "util/util_opengl.h"
#include "util/util_time.h"
@@ -77,8 +78,13 @@ std::ostream& operator <<(std::ostream &os,
Device::~Device()
{
- if(!background && vertex_buffer != 0) {
- glDeleteBuffers(1, &vertex_buffer);
+ if(!background) {
+ if(vertex_buffer != 0) {
+ glDeleteBuffers(1, &vertex_buffer);
+ }
+ if(fallback_shader_program != 0) {
+ glDeleteProgram(fallback_shader_program);
+ }
}
}
@@ -100,125 +106,266 @@ void Device::pixels_free(device_memory& mem)
mem_free(mem);
}
-void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int dx, int dy, int width, int height, bool transparent,
- const DeviceDrawParams &draw_params)
+/* TODO move shaders to standalone .glsl file. */
+const char *FALLBACK_VERTEX_SHADER =
+"#version 330\n"
+"uniform vec2 fullscreen;\n"
+"in vec2 texCoord;\n"
+"in vec2 pos;\n"
+"out vec2 texCoord_interp;\n"
+"\n"
+"vec2 normalize_coordinates()\n"
+"{\n"
+" return (vec2(2.0) * (pos / fullscreen)) - vec2(1.0);\n"
+"}\n"
+"\n"
+"void main()\n"
+"{\n"
+" gl_Position = vec4(normalize_coordinates(), 0.0, 1.0);\n"
+" texCoord_interp = texCoord;\n"
+"}\n\0";
+
+const char *FALLBACK_FRAGMENT_SHADER =
+"#version 330\n"
+"uniform sampler2D image_texture;\n"
+"in vec2 texCoord_interp;\n"
+"out vec4 fragColor;\n"
+"\n"
+"void main()\n"
+"{\n"
+" fragColor = texture(image_texture, texCoord_interp);\n"
+"}\n\0";
+
+static void shader_print_errors(const char *task, const char *log, const char *code)
{
- pixels_copy_from(rgba, y, w, h);
+ LOG(ERROR) << "Shader: " << task << " error:";
+ LOG(ERROR) << "===== shader string ====";
- if(transparent) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ stringstream stream(code);
+ string partial;
+
+ int line = 1;
+ while(getline(stream, partial, '\n')) {
+ if(line < 10) {
+ LOG(ERROR) << " " << line << " " << partial;
+ }
+ else {
+ LOG(ERROR) << line << " " << partial;
+ }
+ line++;
}
+ LOG(ERROR) << log;
+}
- glColor3f(1.0f, 1.0f, 1.0f);
+static int bind_fallback_shader(void)
+{
+ GLint status;
+ GLchar log[5000];
+ GLsizei length = 0;
+ GLuint program = 0;
- if(rgba.data_type == TYPE_HALF) {
- /* for multi devices, this assumes the inefficient method that we allocate
- * all pixels on the device even though we only render to a subset */
- GLhalf *data_pointer = (GLhalf*)rgba.data_pointer;
- float vbuffer[16], *basep;
- float *vp = NULL;
+ struct Shader {
+ const char *source;
+ GLenum type;
+ } shaders[2] = {
+ {FALLBACK_VERTEX_SHADER, GL_VERTEX_SHADER},
+ {FALLBACK_FRAGMENT_SHADER, GL_FRAGMENT_SHADER}
+ };
- data_pointer += 4*y*w;
+ program = glCreateProgram();
- /* draw half float texture, GLSL shader for display transform assumed to be bound */
- GLuint texid;
- glGenTextures(1, &texid);
- glBindTexture(GL_TEXTURE_2D, texid);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, w, h, 0, GL_RGBA, GL_HALF_FLOAT, data_pointer);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ for(int i = 0; i < 2; i++) {
+ GLuint shader = glCreateShader(shaders[i].type);
+
+ string source_str = shaders[i].source;
+ const char *c_str = source_str.c_str();
- glEnable(GL_TEXTURE_2D);
+ glShaderSource(shader, 1, &c_str, NULL);
+ glCompileShader(shader);
- if(draw_params.bind_display_space_shader_cb) {
- draw_params.bind_display_space_shader_cb();
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+
+ if(!status) {
+ glGetShaderInfoLog(shader, sizeof(log), &length, log);
+ shader_print_errors("compile", log, c_str);
+ return 0;
}
- if(GLEW_VERSION_1_5) {
- if(!vertex_buffer)
- glGenBuffers(1, &vertex_buffer);
+ glAttachShader(program, shader);
+ }
+
+ /* Link output. */
+ glBindFragDataLocation(program, 0, "fragColor");
- glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
- /* invalidate old contents - avoids stalling if buffer is still waiting in queue to be rendered */
- glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW);
+ /* Link and error check. */
+ glLinkProgram(program);
- vp = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+ glGetProgramiv(program, GL_LINK_STATUS, &status);
+ if(!status) {
+ glGetShaderInfoLog(program, sizeof(log), &length, log);
+ shader_print_errors("linking", log, FALLBACK_VERTEX_SHADER);
+ shader_print_errors("linking", log, FALLBACK_FRAGMENT_SHADER);
+ return 0;
+ }
- basep = NULL;
+ return program;
+}
+
+bool Device::bind_fallback_display_space_shader(const float width, const float height)
+{
+ if(fallback_status == FALLBACK_SHADER_STATUS_ERROR) {
+ return false;
+ }
+
+ if(fallback_status == FALLBACK_SHADER_STATUS_NONE) {
+ fallback_shader_program = bind_fallback_shader();
+ fallback_status = FALLBACK_SHADER_STATUS_ERROR;
+
+ if (fallback_shader_program == 0) {
+ return false;
}
- else {
- basep = vbuffer;
- vp = vbuffer;
+
+ glUseProgram(fallback_shader_program);
+ image_texture_location = glGetUniformLocation(fallback_shader_program, "image_texture");
+ if(image_texture_location < 0) {
+ LOG(ERROR) << "Shader doesn't containt the 'image_texture' uniform.";
+ return false;
}
- if(vp) {
- /* texture coordinate - vertex pair */
- vp[0] = 0.0f;
- vp[1] = 0.0f;
- vp[2] = dx;
- vp[3] = dy;
-
- vp[4] = 1.0f;
- vp[5] = 0.0f;
- vp[6] = (float)width + dx;
- vp[7] = dy;
-
- vp[8] = 1.0f;
- vp[9] = 1.0f;
- vp[10] = (float)width + dx;
- vp[11] = (float)height + dy;
-
- vp[12] = 0.0f;
- vp[13] = 1.0f;
- vp[14] = dx;
- vp[15] = (float)height + dy;
-
- if(vertex_buffer)
- glUnmapBuffer(GL_ARRAY_BUFFER);
+ fullscreen_location = glGetUniformLocation(fallback_shader_program, "fullscreen");
+ if(fullscreen_location < 0) {
+ LOG(ERROR) << "Shader doesn't containt the 'fullscreen' uniform.";
+ return false;
}
- glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), basep);
- glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), ((char *)basep) + 2 * sizeof(float));
+ fallback_status = FALLBACK_SHADER_STATUS_SUCCESS;
+ }
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ /* Run this every time. */
+ glUseProgram(fallback_shader_program);
+ glUniform1i(image_texture_location, 0);
+ glUniform2f(fullscreen_location, width, height);
+ return true;
+}
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+void Device::draw_pixels(
+ device_memory& rgba, int y,
+ int w, int h, int width, int height,
+ int dx, int dy, int dw, int dh,
+ bool transparent, const DeviceDrawParams &draw_params)
+{
+ const bool use_fallback_shader = (draw_params.bind_display_space_shader_cb == NULL);
+ pixels_copy_from(rgba, y, w, h);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glDisableClientState(GL_VERTEX_ARRAY);
+ GLuint texid;
+ glGenTextures(1, &texid);
+ glBindTexture(GL_TEXTURE_2D, texid);
- if(vertex_buffer) {
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- }
+ if(rgba.data_type == TYPE_HALF) {
+ GLhalf *data_pointer = (GLhalf*)rgba.data_pointer;
+ data_pointer += 4 * y * w;
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, w, h, 0, GL_RGBA, GL_HALF_FLOAT, data_pointer);
+ }
+ else {
+ uint8_t *data_pointer = (uint8_t*)rgba.data_pointer;
+ data_pointer += 4 * y * w;
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data_pointer);
+ }
- if(draw_params.unbind_display_space_shader_cb) {
- draw_params.unbind_display_space_shader_cb();
- }
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glEnable(GL_TEXTURE_2D);
+
+ if(transparent) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
- glBindTexture(GL_TEXTURE_2D, 0);
- glDisable(GL_TEXTURE_2D);
- glDeleteTextures(1, &texid);
+ GLint shader_program;
+ if(use_fallback_shader) {
+ if (!bind_fallback_display_space_shader(dw, dh)) {
+ return;
+ }
+ shader_program = fallback_shader_program;
}
else {
- /* fallback for old graphics cards that don't support GLSL, half float,
- * and non-power-of-two textures */
- glPixelZoom((float)width/(float)w, (float)height/(float)h);
- glRasterPos2f(dx, dy);
+ draw_params.bind_display_space_shader_cb();
+ glGetIntegerv(GL_CURRENT_PROGRAM, &shader_program);
+ }
+
+ if(!vertex_buffer) {
+ glGenBuffers(1, &vertex_buffer);
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
+ /* invalidate old contents - avoids stalling if buffer is still waiting in queue to be rendered */
+ glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW);
+
+ float *vpointer = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+
+ if(vpointer) {
+ /* texture coordinate - vertex pair */
+ vpointer[0] = 0.0f;
+ vpointer[1] = 0.0f;
+ vpointer[2] = dx;
+ vpointer[3] = dy;
- uint8_t *pixels = (uint8_t*)rgba.data_pointer;
+ vpointer[4] = 1.0f;
+ vpointer[5] = 0.0f;
+ vpointer[6] = (float)width + dx;
+ vpointer[7] = dy;
- pixels += 4*y*w;
+ vpointer[8] = 1.0f;
+ vpointer[9] = 1.0f;
+ vpointer[10] = (float)width + dx;
+ vpointer[11] = (float)height + dy;
- glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+ vpointer[12] = 0.0f;
+ vpointer[13] = 1.0f;
+ vpointer[14] = dx;
+ vpointer[15] = (float)height + dy;
- glRasterPos2f(0.0f, 0.0f);
- glPixelZoom(1.0f, 1.0f);
+ if(vertex_buffer) {
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+ }
}
- if(transparent)
+ GLuint vertex_array_object;
+ GLuint position_attribute, texcoord_attribute;
+
+ glGenVertexArrays(1, &vertex_array_object);
+ glBindVertexArray(vertex_array_object);
+
+ texcoord_attribute = glGetAttribLocation(shader_program, "texCoord");
+ position_attribute = glGetAttribLocation(shader_program, "pos");
+
+ glEnableVertexAttribArray(texcoord_attribute);
+ glEnableVertexAttribArray(position_attribute);
+
+ glVertexAttribPointer(texcoord_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)0);
+ glVertexAttribPointer(position_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)(sizeof(float) * 2));
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ if(vertex_buffer) {
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+
+ if(use_fallback_shader) {
+ glUseProgram(0);
+ }
+ else {
+ draw_params.unbind_display_space_shader_cb();
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDisable(GL_TEXTURE_2D);
+ glDeleteTextures(1, &texid);
+
+ if(transparent) {
glDisable(GL_BLEND);
+ }
}
Device *Device::create(DeviceInfo& info, Stats &stats, bool background)
diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index 26d6d380a10..8736a6927e0 100644
--- a/intern/cycles/device/device.h
+++ b/intern/cycles/device/device.h
@@ -236,13 +236,26 @@ struct DeviceDrawParams {
class Device {
friend class device_sub_ptr;
protected:
- Device(DeviceInfo& info_, Stats &stats_, bool background) : background(background), vertex_buffer(0), info(info_), stats(stats_) {}
+ enum {
+ FALLBACK_SHADER_STATUS_NONE = 0,
+ FALLBACK_SHADER_STATUS_ERROR,
+ FALLBACK_SHADER_STATUS_SUCCESS,
+ };
+
+ Device(DeviceInfo& info_, Stats &stats_, bool background) : background(background),
+ vertex_buffer(0),
+ fallback_status(FALLBACK_SHADER_STATUS_NONE), fallback_shader_program(0),
+ info(info_), stats(stats_) {}
bool background;
string error_msg;
/* used for real time display */
unsigned int vertex_buffer;
+ int fallback_status, fallback_shader_program;
+ int image_texture_location, fullscreen_location;
+
+ bool bind_fallback_display_space_shader(const float width, const float height);
virtual device_ptr mem_alloc_sub_ptr(device_memory& /*mem*/, int /*offset*/, int /*size*/, MemoryType /*type*/)
{
@@ -317,9 +330,10 @@ public:
virtual void task_cancel() = 0;
/* opengl drawing */
- virtual void draw_pixels(device_memory& mem, int y, int w, int h,
- int dx, int dy, int width, int height, bool transparent,
- const DeviceDrawParams &draw_params);
+ virtual void draw_pixels(device_memory& mem, int y,
+ int w, int h, int width, int height,
+ int dx, int dy, int dw, int dh,
+ bool transparent, const DeviceDrawParams &draw_params);
#ifdef WITH_NETWORK
/* networking */
diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp
index 6769ed0229e..c68eba7bef6 100644
--- a/intern/cycles/device/device_cuda.cpp
+++ b/intern/cycles/device/device_cuda.cpp
@@ -1632,10 +1632,14 @@ public:
}
}
- void draw_pixels(device_memory& mem, int y, int w, int h, int dx, int dy, int width, int height, bool transparent,
+ void draw_pixels(
+ device_memory& mem, int y,
+ int w, int h, int width, int height,
+ int dx, int dy, int dw, int dh, bool transparent,
const DeviceDrawParams &draw_params)
{
if(!background) {
+ const bool use_fallback_shader = (draw_params.bind_display_space_shader_cb == NULL);
PixelMem pmem = pixel_mem_map[mem.device_pointer];
float *vpointer;
@@ -1652,10 +1656,12 @@ public:
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO);
glBindTexture(GL_TEXTURE_2D, pmem.cuTexId);
- if(mem.data_type == TYPE_HALF)
+ if(mem.data_type == TYPE_HALF) {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_HALF_FLOAT, (void*)offset);
- else
+ }
+ else {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)offset);
+ }
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glEnable(GL_TEXTURE_2D);
@@ -1665,14 +1671,21 @@ public:
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
- glColor3f(1.0f, 1.0f, 1.0f);
-
- if(draw_params.bind_display_space_shader_cb) {
+ GLint shader_program;
+ if(use_fallback_shader) {
+ if(!bind_fallback_display_space_shader(dw, dh)) {
+ return;
+ }
+ shader_program = fallback_shader_program;
+ }
+ else {
draw_params.bind_display_space_shader_cb();
+ glGetIntegerv(GL_CURRENT_PROGRAM, &shader_program);
}
- if(!vertex_buffer)
+ if(!vertex_buffer) {
glGenBuffers(1, &vertex_buffer);
+ }
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
/* invalidate old contents - avoids stalling if buffer is still waiting in queue to be rendered */
@@ -1705,25 +1718,33 @@ public:
glUnmapBuffer(GL_ARRAY_BUFFER);
}
- glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), 0);
- glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), (char *)NULL + 2 * sizeof(float));
+ GLuint vertex_array_object;
+ GLuint position_attribute, texcoord_attribute;
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glGenVertexArrays(1, &vertex_array_object);
+ glBindVertexArray(vertex_array_object);
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ texcoord_attribute = glGetAttribLocation(shader_program, "texCoord");
+ position_attribute = glGetAttribLocation(shader_program, "pos");
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glDisableClientState(GL_VERTEX_ARRAY);
+ glEnableVertexAttribArray(texcoord_attribute);
+ glEnableVertexAttribArray(position_attribute);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glVertexAttribPointer(texcoord_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)0);
+ glVertexAttribPointer(position_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)(sizeof(float) * 2));
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- if(draw_params.unbind_display_space_shader_cb) {
+ if(use_fallback_shader) {
+ glUseProgram(0);
+ }
+ else {
draw_params.unbind_display_space_shader_cb();
}
- if(transparent)
+ if(transparent) {
glDisable(GL_BLEND);
+ }
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
@@ -1733,7 +1754,7 @@ public:
return;
}
- Device::draw_pixels(mem, y, w, h, dx, dy, width, height, transparent, draw_params);
+ Device::draw_pixels(mem, y, w, h, width, height, dx, dy, dw, dh, transparent, draw_params);
}
void thread_run(DeviceTask *task)
diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp
index bc505b676fc..35ae0303d6e 100644
--- a/intern/cycles/device/device_multi.cpp
+++ b/intern/cycles/device/device_multi.cpp
@@ -254,8 +254,11 @@ public:
mem.device_pointer = tmp;
}
- void draw_pixels(device_memory& rgba, int y, int w, int h, int dx, int dy, int width, int height, bool transparent,
- const DeviceDrawParams &draw_params)
+ void draw_pixels(
+ device_memory& rgba, int y,
+ int w, int h, int width, int height,
+ int dx, int dy, int dw, int dh,
+ bool transparent, const DeviceDrawParams &draw_params)
{
device_ptr tmp = rgba.device_pointer;
int i = 0, sub_h = h/devices.size();
@@ -269,7 +272,7 @@ public:
/* adjust math for w/width */
rgba.device_pointer = sub.ptr_map[tmp];
- sub.device->draw_pixels(rgba, sy, w, sh, dx, sdy, width, sheight, transparent, draw_params);
+ sub.device->draw_pixels(rgba, sy, w, sh, width, sheight, dx, sdy, dw, dh, transparent, draw_params);
i++;
}
diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp
index cf402c3f214..ff6f40c010e 100644
--- a/intern/cycles/render/buffers.cpp
+++ b/intern/cycles/render/buffers.cpp
@@ -428,7 +428,11 @@ void DisplayBuffer::draw(Device *device, const DeviceDrawParams& draw_params)
if(draw_width != 0 && draw_height != 0) {
device_memory& rgba = rgba_data();
- device->draw_pixels(rgba, 0, draw_width, draw_height, params.full_x, params.full_y, params.width, params.height, transparent, draw_params);
+ device->draw_pixels(
+ rgba, 0,
+ draw_width, draw_height, params.width, params.height,
+ params.full_x, params.full_y, params.full_width, params.full_height,
+ transparent, draw_params);
}
}
diff --git a/intern/cycles/util/util_opengl.h b/intern/cycles/util/util_opengl.h
index 0b5462e0a09..7a8d5eec1f9 100644
--- a/intern/cycles/util/util_opengl.h
+++ b/intern/cycles/util/util_opengl.h
@@ -20,12 +20,6 @@
/* OpenGL header includes, used everywhere we use OpenGL, to deal with
* platform differences in one central place. */
-#ifdef WITH_GLEW_MX
-# include "glew-mx.h"
-#else
-# include <GL/glew.h>
-# define mxCreateContext() glewInit()
-# define mxMakeCurrentContext(x) (x)
-#endif
+#include <GL/glew.h>
#endif /* __UTIL_OPENGL_H__ */
diff --git a/intern/cycles/util/util_view.cpp b/intern/cycles/util/util_view.cpp
index 10d86167921..7b453d123b8 100644
--- a/intern/cycles/util/util_view.cpp
+++ b/intern/cycles/util/util_view.cpp
@@ -252,7 +252,7 @@ void view_main_loop(const char *title, int width, int height,
glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
glutCreateWindow(title);
- mxMakeCurrentContext(mxCreateContext());
+ glewInit();
view_reshape(width, height);
diff --git a/intern/elbeem/intern/solver_control.cpp b/intern/elbeem/intern/solver_control.cpp
index c3015b82f0a..d7ed1a5a7ef 100644
--- a/intern/elbeem/intern/solver_control.cpp
+++ b/intern/elbeem/intern/solver_control.cpp
@@ -873,156 +873,4 @@ LbmFsgrSolver::handleCpdata()
// warning, may return before
}
-#if LBM_USE_GUI==1
-
-#define USE_GLUTILITIES
-#include "../gui/gui_utilities.h"
-
-void LbmFsgrSolver::cpDebugDisplay(int dispset)
-{
- for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) {
- ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts;
- //ControlParticles *cpmotion = mpControl->mCons[cpssi]->mCpmotion;
- // display cp parts
- const bool cpCubes = false;
- const bool cpDots = true;
- const bool cpCpdist = true;
- const bool cpHideIna = true;
- glShadeModel(GL_FLAT);
- glDisable( GL_LIGHTING ); // dont light lines
-
- // dot influence
- if((mpControl->mDebugCpscale>0.) && cpDots) {
- glPointSize(mpControl->mDebugCpscale * 8.);
- glBegin(GL_POINTS);
- for(int i=0; i<cparts->getSize(); i++) {
- if((cpHideIna)&&( (cparts->getParticle(i)->influence<=0.) || (cparts->getParticle(i)->size<=0.) )) continue;
- ntlVec3Gfx org( vec2G(cparts->getParticle(i)->pos ) );
- //LbmFloat halfsize = 0.5;
- LbmFloat scale = cparts->getParticle(i)->densityWeight;
- //glColor4f( scale,scale,scale,scale );
- glColor4f( 0.,scale,0.,scale );
- glVertex3f( org[0],org[1],org[2] );
- //errMsg("lbmDebugDisplay","CP "<<i<<" at "<<org); // DEBUG
- }
- glEnd();
- }
-
- // cp positions
- if((mpControl->mDebugCpscale>0.) && cpDots) {
- glPointSize(mpControl->mDebugCpscale * 3.);
- glBegin(GL_POINTS);
- glColor3f( 0,1,0 );
- }
- for(int i=0; i<cparts->getSize(); i++) {
- if((cpHideIna)&&( (cparts->getParticle(i)->influence<=0.) || (cparts->getParticle(i)->size<=0.) )) continue;
- ntlVec3Gfx org( vec2G(cparts->getParticle(i)->pos ) );
- LbmFloat halfsize = 0.5;
- LbmFloat scale = cparts->getRadiusAtt() * cparts->getParticle(i)->densityWeight;
- if(cpCubes){ glLineWidth( 1 );
- glColor3f( 1,1,1 );
- ntlVec3Gfx s = org-(halfsize * (scale));
- ntlVec3Gfx e = org+(halfsize * (scale));
- drawCubeWire( s,e ); }
- if((mpControl->mDebugCpscale>0.) && cpDots) {
- glVertex3f( org[0],org[1],org[2] );
- }
- }
- if(cpDots) glEnd();
-
- if(mpControl->mDebugAvgVelScale>0.) {
- const float scale = mpControl->mDebugAvgVelScale;
-
- glColor3f( 1.0,1.0,1 );
- glBegin(GL_LINES);
- for(int i=0; i<cparts->getSize(); i++) {
- if((cpHideIna)&&( (cparts->getParticle(i)->influence<=0.) || (cparts->getParticle(i)->size<=0.) )) continue;
- ntlVec3Gfx org( vec2G(cparts->getParticle(i)->pos ) );
-
- //errMsg("CPAVGVEL","i"<<i<<" pos"<<org<<" av"<<cparts->getParticle(i)->avgVel);// DEBUG
- float dx = cparts->getParticle(i)->avgVel[0];
- float dy = cparts->getParticle(i)->avgVel[1];
- float dz = cparts->getParticle(i)->avgVel[2];
- dx *= scale; dy *= scale; dz *= scale;
- glVertex3f( org[0],org[1],org[2] );
- glVertex3f( org[0]+dx,org[1]+dy,org[2]+dz );
- }
- glEnd();
- } // */
-
- if( (LBMDIM==2) && (cpCpdist) ) {
-
- // debug, for use of e.g. LBMGET_FORCE LbmControlData *mpControl = this;
-# define TESTGET_FORCE(lev,i,j,k) mpControl->mCpForces[lev][ ((k*mLevel[lev].lSizey)+j)*mLevel[lev].lSizex+i ]
-
- glBegin(GL_LINES);
- //const int lev=0;
- for(int lev=0; lev<=mMaxRefine; lev++) {
- FSGR_FORIJK_BOUNDS(lev) {
- LbmVec pos = LbmVec(
- ((mvGeoEnd[0]-mvGeoStart[0])/(LbmFloat)mLevel[lev].lSizex) * ((LbmFloat)i+0.5) + mvGeoStart[0],
- ((mvGeoEnd[1]-mvGeoStart[1])/(LbmFloat)mLevel[lev].lSizey) * ((LbmFloat)j+0.5) + mvGeoStart[1],
- ((mvGeoEnd[2]-mvGeoStart[2])/(LbmFloat)mLevel[lev].lSizez) * ((LbmFloat)k+0.5) + mvGeoStart[2] );
- if(LBMDIM==2) pos[2] = ((mvGeoEnd[2]-mvGeoStart[2])*0.5 + mvGeoStart[2]);
-
- if((mpControl->mDebugMaxdScale>0.) && (TESTGET_FORCE(lev,i,j,k).weightAtt<=0.) )
- if(TESTGET_FORCE(lev,i,j,k).maxDistance>=0.)
- if(TESTGET_FORCE(lev,i,j,k).maxDistance<CPF_MAXDINIT ) {
- const float scale = mpControl->mDebugMaxdScale*10001.;
- float dx = TESTGET_FORCE(lev,i,j,k).forceMaxd[0];
- float dy = TESTGET_FORCE(lev,i,j,k).forceMaxd[1];
- float dz = TESTGET_FORCE(lev,i,j,k).forceMaxd[2];
- dx *= scale; dy *= scale; dz *= scale;
- glColor3f( 0,1,0 );
- glVertex3f( pos[0],pos[1],pos[2] );
- glVertex3f( pos[0]+dx,pos[1]+dy,pos[2]+dz );
- } // */
- if((mpControl->mDebugAttScale>0.) && (TESTGET_FORCE(lev,i,j,k).weightAtt>0.)) {
- const float scale = mpControl->mDebugAttScale*100011.;
- float dx = TESTGET_FORCE(lev,i,j,k).forceAtt[0];
- float dy = TESTGET_FORCE(lev,i,j,k).forceAtt[1];
- float dz = TESTGET_FORCE(lev,i,j,k).forceAtt[2];
- dx *= scale; dy *= scale; dz *= scale;
- glColor3f( 1,0,0 );
- glVertex3f( pos[0],pos[1],pos[2] );
- glVertex3f( pos[0]+dx,pos[1]+dy,pos[2]+dz );
- } // */
- // why check maxDistance?
- if((mpControl->mDebugVelScale>0.) && (TESTGET_FORCE(lev,i,j,k).maxDistance+TESTGET_FORCE(lev,i,j,k).weightVel>0.)) {
- float scale = mpControl->mDebugVelScale*1.;
- float wvscale = TESTGET_FORCE(lev,i,j,k).weightVel;
- float dx = TESTGET_FORCE(lev,i,j,k).forceVel[0];
- float dy = TESTGET_FORCE(lev,i,j,k).forceVel[1];
- float dz = TESTGET_FORCE(lev,i,j,k).forceVel[2];
- scale *= wvscale;
- dx *= scale; dy *= scale; dz *= scale;
- glColor3f( 0.2,0.2,1 );
- glVertex3f( pos[0],pos[1],pos[2] );
- glVertex3f( pos[0]+dx,pos[1]+dy,pos[2]+dz );
- } // */
- if((mpControl->mDebugCompavScale>0.) && (TESTGET_FORCE(lev,i,j,k).compAvWeight>0.)) {
- const float scale = mpControl->mDebugCompavScale*1.;
- float dx = TESTGET_FORCE(lev,i,j,k).compAv[0];
- float dy = TESTGET_FORCE(lev,i,j,k).compAv[1];
- float dz = TESTGET_FORCE(lev,i,j,k).compAv[2];
- dx *= scale; dy *= scale; dz *= scale;
- glColor3f( 0.2,0.2,1 );
- glVertex3f( pos[0],pos[1],pos[2] );
- glVertex3f( pos[0]+dx,pos[1]+dy,pos[2]+dz );
- } // */
- } // att,maxd
- }
- glEnd();
- }
- } // cpssi
-
- //fprintf(stderr,"BLA\n");
- glEnable( GL_LIGHTING ); // dont light lines
- glShadeModel(GL_SMOOTH);
-}
-
-#else // LBM_USE_GUI==1
void LbmFsgrSolver::cpDebugDisplay(int dispset) { }
-#endif // LBM_USE_GUI==1
-
-
diff --git a/intern/elbeem/intern/solver_util.cpp b/intern/elbeem/intern/solver_util.cpp
index f0c7bce2b4e..4bcc3640d72 100644
--- a/intern/elbeem/intern/solver_util.cpp
+++ b/intern/elbeem/intern/solver_util.cpp
@@ -1677,223 +1677,6 @@ LbmFloat& LbmFsgrSolver::debRAC(LbmFloat* s,int l) {
* GUI&debugging functions
*****************************************************************************/
-
-#if LBM_USE_GUI==1
-#define USE_GLUTILITIES
-#include "../gui/gui_utilities.h"
-
-//! display a single node
-void LbmFsgrSolver::debugDisplayNode(int dispset, CellIdentifierInterface* cell ) {
- //debugOut(" DD: "<<cell->getAsString() , 10);
- ntlVec3Gfx org = this->getCellOrigin( cell );
- ntlVec3Gfx halfsize = this->getCellSize( cell );
- int set = this->getCellSet( cell );
- //debugOut(" DD: "<<cell->getAsString()<<" "<< (dispset->type) , 10);
-
- bool showcell = true;
- int linewidth = 1;
- ntlColor col(0.5);
- LbmFloat cscale = 1.0; //dispset->scale;
-
-#define DRAWDISPCUBE(col,scale) \
- { glLineWidth( linewidth ); \
- glColor3f( (col)[0], (col)[1], (col)[2]); \
- ntlVec3Gfx s = org-(halfsize * (scale)); \
- ntlVec3Gfx e = org+(halfsize * (scale)); \
- drawCubeWire( s,e ); }
-
- CellFlagType flag = this->getCellFlag(cell, set );
- // always check types
- if(flag& CFInvalid ) { if(!guiShowInvalid ) return; }
- if(flag& CFUnused ) { if(!guiShowInvalid ) return; }
- if(flag& CFEmpty ) { if(!guiShowEmpty ) return; }
- if(flag& CFInter ) { if(!guiShowInterface) return; }
- if(flag& CFNoDelete ) { if(!guiShowNoDelete ) return; }
- if(flag& CFBnd ) { if(!guiShowBnd ) return; }
-
- // only dismiss one of these types
- if(flag& CFGrFromCoarse) { if(!guiShowCoarseInner ) return; } // inner not really interesting
- else
- if(flag& CFGrFromFine) { if(!guiShowCoarseBorder ) return; }
- else
- if(flag& CFFluid ) { if(!guiShowFluid ) return; }
-
- switch(dispset) {
- case FLUIDDISPNothing: {
- showcell = false;
- } break;
- case FLUIDDISPCelltypes: {
- cscale = 0.5;
-
- if(flag& CFNoDelete) { // debug, mark nodel cells
- ntlColor ccol(0.7,0.0,0.0);
- DRAWDISPCUBE(ccol, 0.1);
- }
- if(flag& CFPersistMask) { // mark persistent flags
- ntlColor ccol(0.5);
- DRAWDISPCUBE(ccol, 0.125);
- }
- if(flag& CFNoBndFluid) { // mark persistent flags
- ntlColor ccol(0,0,1);
- DRAWDISPCUBE(ccol, 0.075);
- }
-
- if(flag& CFInvalid) {
- cscale = 0.50;
- col = ntlColor(0.0,0,0.0);
- }
- else if(flag& CFBnd) {
- cscale = 0.59;
- col = ntlColor(0.4);
- }
-
- else if(flag& CFInter) {
- cscale = 0.55;
- col = ntlColor(0,1,1);
-
- } else if(flag& CFGrFromCoarse) {
- // draw as - with marker
- ntlColor col2(0.0,1.0,0.3);
- DRAWDISPCUBE(col2, 0.1);
- cscale = 0.5;
- showcell=false; // DEBUG
- }
- else if(flag& CFFluid) {
- cscale = 0.5;
- if(flag& CFGrToFine) {
- ntlColor col2(0.5,0.0,0.5);
- DRAWDISPCUBE(col2, 0.1);
- col = ntlColor(0,0,1);
- }
- if(flag& CFGrFromFine) {
- ntlColor col2(1.0,1.0,0.0);
- DRAWDISPCUBE(col2, 0.1);
- col = ntlColor(0,0,1);
- } else if(flag& CFGrFromCoarse) {
- // draw as fluid with marker
- ntlColor col2(0.0,1.0,0.3);
- DRAWDISPCUBE(col2, 0.1);
- col = ntlColor(0,0,1);
- } else {
- col = ntlColor(0,0,1);
- }
- }
- else if(flag& CFEmpty) {
- showcell=false;
- }
-
- } break;
- case FLUIDDISPVelocities: {
- // dont use cube display
- LbmVec vel = this->getCellVelocity( cell, set );
- glBegin(GL_LINES);
- glColor3f( 0.0,0.0,0.0 );
- glVertex3f( org[0], org[1], org[2] );
- org += vec2G(vel * 10.0 * cscale);
- glColor3f( 1.0,1.0,1.0 );
- glVertex3f( org[0], org[1], org[2] );
- glEnd();
- showcell = false;
- } break;
- case FLUIDDISPCellfills: {
- cscale = 0.5;
- if(flag& CFFluid) {
- cscale = 0.75;
- col = ntlColor(0,0,0.5);
- }
- else if(flag& CFInter) {
- cscale = 0.75 * this->getCellMass(cell,set);
- col = ntlColor(0,1,1);
- }
- else {
- showcell=false;
- }
-
- if( ABS(this->getCellMass(cell,set)) < 10.0 ) {
- cscale = 0.75 * this->getCellMass(cell,set);
- } else {
- showcell = false;
- }
- if(cscale>0.0) {
- col = ntlColor(0,1,1);
- } else {
- col = ntlColor(1,1,0);
- }
- // TODO
- } break;
- case FLUIDDISPDensity: {
- LbmFloat rho = this->getCellDensity(cell,set);
- cscale = rho*rho * 0.25;
- col = ntlColor( MIN(0.5+cscale,1.0) , MIN(0.0+cscale,1.0), MIN(0.0+cscale,1.0) );
- cscale *= 2.0;
- } break;
- case FLUIDDISPGrid: {
- cscale = 0.59;
- col = ntlColor(1.0);
- } break;
- default: {
- cscale = 0.5;
- col = ntlColor(1.0,0.0,0.0);
- } break;
- }
-
- if(!showcell) return;
- if(cscale==0.0) return; // dont draw zero values
- DRAWDISPCUBE(col, cscale);
-}
-
-//! debug display function
-// D has to implement the CellIterator interface
-void LbmFsgrSolver::lbmDebugDisplay(int dispset) {
- // DEBUG always display testdata
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(mUseTestdata){
- cpDebugDisplay(dispset);
- mpTest->testDebugDisplay(dispset);
- }
-#endif // LBM_INCLUDE_TESTSOLVERS==1
- if(dispset<=FLUIDDISPNothing) return;
- //if(!dispset->on) return;
- glDisable( GL_LIGHTING ); // dont light lines
-
-#if LBM_INCLUDE_TESTSOLVERS==1
- if((!mUseTestdata)|| (mUseTestdata)&&(mpTest->mFarfMode<=0)) {
-#endif // LBM_INCLUDE_TESTSOLVERS==1
-
- LbmFsgrSolver::CellIdentifier cid = this->getFirstCell();
- for(; this->noEndCell( cid );
- this->advanceCell( cid ) ) {
- this->debugDisplayNode(dispset, cid );
- }
- delete cid;
-
-#if LBM_INCLUDE_TESTSOLVERS==1
- } // 3d check
-#endif // LBM_INCLUDE_TESTSOLVERS==1
-
- glEnable( GL_LIGHTING ); // dont light lines
-}
-
-//! debug display function
-// D has to implement the CellIterator interface
-void LbmFsgrSolver::lbmMarkedCellDisplay() {
- //fluidDispSettings dispset;
- // trick - display marked cells as grid displa -> white, big
- int dispset = FLUIDDISPGrid;
- glDisable( GL_LIGHTING ); // dont light lines
-
- LbmFsgrSolver::CellIdentifier cid = this->markedGetFirstCell();
- while(cid) {
- this->debugDisplayNode(dispset, cid );
- cid = this->markedAdvanceCell();
- }
- delete cid;
-
- glEnable( GL_LIGHTING ); // dont light lines
-}
-
-#endif // LBM_USE_GUI==1
-
//! display a single node
void LbmFsgrSolver::debugPrintNodeInfo(CellIdentifierInterface* cell, int forceSet) {
//string printInfo,
diff --git a/intern/gawain/CMakeLists.txt b/intern/gawain/CMakeLists.txt
new file mode 100644
index 00000000000..48392012176
--- /dev/null
+++ b/intern/gawain/CMakeLists.txt
@@ -0,0 +1,40 @@
+
+set(INC
+ gawain
+)
+
+set(INC_SYS
+ ${GLEW_INCLUDE_PATH}
+)
+
+set(SRC
+ src/attrib_binding.c
+ src/batch.c
+ src/element.c
+ src/buffer_id.cpp
+ src/immediate.c
+ src/imm_util.c
+ src/primitive.c
+ src/shader_interface.c
+ src/vertex_buffer.c
+ src/vertex_format.c
+
+ gawain/attrib_binding.h
+ gawain/attrib_binding_private.h
+ gawain/batch.h
+ gawain/buffer_id.h
+ gawain/common.h
+ gawain/element.h
+ gawain/imm_util.h
+ gawain/immediate.h
+ gawain/primitive.h
+ gawain/primitive_private.h
+ gawain/shader_interface.h
+ gawain/vertex_buffer.h
+ gawain/vertex_format.h
+ gawain/vertex_format_private.h
+)
+
+add_definitions(${GL_DEFINITIONS})
+
+blender_add_lib(bf_intern_gawain "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/intern/gawain/gawain/attrib_binding.h b/intern/gawain/gawain/attrib_binding.h
new file mode 100644
index 00000000000..a254f05dc05
--- /dev/null
+++ b/intern/gawain/gawain/attrib_binding.h
@@ -0,0 +1,19 @@
+
+// Gawain vertex attribute binding
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+#include "common.h"
+
+typedef struct {
+ uint64_t loc_bits; // store 4 bits for each of the 16 attribs
+ uint16_t enabled_bits; // 1 bit for each attrib
+} Gwn_AttrBinding;
diff --git a/intern/gawain/gawain/attrib_binding_private.h b/intern/gawain/gawain/attrib_binding_private.h
new file mode 100644
index 00000000000..53fdecff9ce
--- /dev/null
+++ b/intern/gawain/gawain/attrib_binding_private.h
@@ -0,0 +1,20 @@
+
+// Gawain vertex attribute binding
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2017 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+#include "vertex_format.h"
+#include "shader_interface.h"
+
+void AttribBinding_clear(Gwn_AttrBinding*);
+
+void get_attrib_locations(const Gwn_VertFormat*, Gwn_AttrBinding*, const Gwn_ShaderInterface*);
+unsigned read_attrib_location(const Gwn_AttrBinding*, unsigned a_idx);
diff --git a/intern/gawain/gawain/batch.h b/intern/gawain/gawain/batch.h
new file mode 100644
index 00000000000..6e2f32c1996
--- /dev/null
+++ b/intern/gawain/gawain/batch.h
@@ -0,0 +1,129 @@
+
+// Gawain geometry batch
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+#include "vertex_buffer.h"
+#include "element.h"
+#include "shader_interface.h"
+
+typedef enum {
+ GWN_BATCH_READY_TO_FORMAT,
+ GWN_BATCH_READY_TO_BUILD,
+ GWN_BATCH_BUILDING,
+ GWN_BATCH_READY_TO_DRAW
+} Gwn_BatchPhase;
+
+#define GWN_BATCH_VBO_MAX_LEN 3
+
+typedef struct Gwn_Batch {
+ // geometry
+ Gwn_VertBuf* verts[GWN_BATCH_VBO_MAX_LEN]; // verts[0] is required, others can be NULL
+ Gwn_IndexBuf* elem; // NULL if element list not needed
+ Gwn_PrimType prim_type;
+ GLenum gl_prim_type;
+
+ // book-keeping
+ GLuint vao_id; // remembers all geometry state (vertex attrib bindings & element buffer)
+ Gwn_BatchPhase phase;
+ bool program_dirty;
+ bool program_in_use;
+
+ // state
+ GLuint program;
+ const Gwn_ShaderInterface* interface;
+} Gwn_Batch;
+
+Gwn_Batch* GWN_batch_create(Gwn_PrimType, Gwn_VertBuf*, Gwn_IndexBuf*);
+void GWN_batch_init(Gwn_Batch*, Gwn_PrimType, Gwn_VertBuf*, Gwn_IndexBuf*);
+
+void GWN_batch_discard(Gwn_Batch*); // verts & elem are not discarded
+void GWN_batch_discard_all(Gwn_Batch*); // including verts & elem
+
+int GWN_batch_vertbuf_add(Gwn_Batch*, Gwn_VertBuf*);
+
+void GWN_batch_program_set(Gwn_Batch*, GLuint program, const Gwn_ShaderInterface*);
+// Entire batch draws with one shader program, but can be redrawn later with another program.
+// Vertex shader's inputs must be compatible with the batch's vertex format.
+
+void GWN_batch_program_use_begin(Gwn_Batch*); // call before Batch_Uniform (temp hack?)
+void GWN_batch_program_use_end(Gwn_Batch*);
+
+void GWN_batch_uniform_1i(Gwn_Batch*, const char* name, int value);
+void GWN_batch_uniform_1b(Gwn_Batch*, const char* name, bool value);
+void GWN_batch_uniform_1f(Gwn_Batch*, const char* name, float value);
+void GWN_batch_uniform_2f(Gwn_Batch*, const char* name, float x, float y);
+void GWN_batch_uniform_3f(Gwn_Batch*, const char* name, float x, float y, float z);
+void GWN_batch_uniform_4f(Gwn_Batch*, const char* name, float x, float y, float z, float w);
+void GWN_batch_uniform_3fv(Gwn_Batch*, const char* name, const float data[3]);
+void GWN_batch_uniform_4fv(Gwn_Batch*, const char* name, const float data[4]);
+
+void GWN_batch_draw(Gwn_Batch*);
+
+
+// clement : temp stuff
+void GWN_batch_draw_stupid(Gwn_Batch*);
+void GWN_batch_draw_stupid_instanced(Gwn_Batch*, unsigned int instance_vbo, int instance_count,
+ int attrib_nbr, int attrib_stride, int attrib_loc[16], int attrib_size[16]);
+void GWN_batch_draw_stupid_instanced_with_batch(Gwn_Batch*, Gwn_Batch*);
+
+
+
+
+
+#if 0 // future plans
+
+// Can multiple batches share a Gwn_VertBuf? Use ref count?
+
+
+// We often need a batch with its own data, to be created and discarded together.
+// WithOwn variants reduce number of system allocations.
+
+typedef struct {
+ Gwn_Batch batch;
+ Gwn_VertBuf verts; // link batch.verts to this
+} BatchWithOwnVertexBuffer;
+
+typedef struct {
+ Gwn_Batch batch;
+ Gwn_IndexBuf elem; // link batch.elem to this
+} BatchWithOwnElementList;
+
+typedef struct {
+ Gwn_Batch batch;
+ Gwn_IndexBuf elem; // link batch.elem to this
+ Gwn_VertBuf verts; // link batch.verts to this
+} BatchWithOwnVertexBufferAndElementList;
+
+Gwn_Batch* create_BatchWithOwnVertexBuffer(Gwn_PrimType, Gwn_VertFormat*, unsigned v_ct, Gwn_IndexBuf*);
+Gwn_Batch* create_BatchWithOwnElementList(Gwn_PrimType, Gwn_VertBuf*, unsigned prim_ct);
+Gwn_Batch* create_BatchWithOwnVertexBufferAndElementList(Gwn_PrimType, Gwn_VertFormat*, unsigned v_ct, unsigned prim_ct);
+// verts: shared, own
+// elem: none, shared, own
+Gwn_Batch* create_BatchInGeneral(Gwn_PrimType, VertexBufferStuff, ElementListStuff);
+
+#endif // future plans
+
+
+/* Macros */
+
+#define GWN_BATCH_DISCARD_SAFE(batch) do { \
+ if (batch != NULL) { \
+ GWN_batch_discard(batch); \
+ batch = NULL; \
+ } \
+} while (0)
+#define BATCH_DISCARD_ALL_SAFE(batch) do { \
+ if (batch != NULL) { \
+ GWN_batch_discard_all(batch); \
+ batch = NULL; \
+ } \
+} while (0)
diff --git a/intern/gawain/gawain/buffer_id.h b/intern/gawain/gawain/buffer_id.h
new file mode 100644
index 00000000000..e978eec67d8
--- /dev/null
+++ b/intern/gawain/gawain/buffer_id.h
@@ -0,0 +1,34 @@
+
+// Gawain buffer IDs
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+// Manage GL buffer IDs in a thread-safe way
+// Use these instead of glGenBuffers & its friends
+// - alloc must be called from main thread
+// - free can be called from any thread
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "common.h"
+
+GLuint GWN_buf_id_alloc(void);
+void GWN_buf_id_free(GLuint buffer_id);
+
+GLuint GWN_vao_alloc(void);
+void GWN_vao_free(GLuint vao_id);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/intern/gawain/gawain/common.h b/intern/gawain/gawain/common.h
new file mode 100644
index 00000000000..e96a3b5c2a2
--- /dev/null
+++ b/intern/gawain/gawain/common.h
@@ -0,0 +1,34 @@
+
+// Gawain common #defines and #includes
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+#if defined(NDEBUG)
+ #define TRUST_NO_ONE 0
+#else
+ // strict error checking, enabled for debug builds during early development
+ #define TRUST_NO_ONE 1
+#endif
+
+#include <GL/glew.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#if TRUST_NO_ONE
+ #include <assert.h>
+#endif
+
+/* GWN_INLINE */
+#if defined(_MSC_VER)
+# define GWN_INLINE static __forceinline
+#else
+# define GWN_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__))
+#endif \ No newline at end of file
diff --git a/intern/gawain/gawain/element.h b/intern/gawain/gawain/element.h
new file mode 100644
index 00000000000..771462be7c5
--- /dev/null
+++ b/intern/gawain/gawain/element.h
@@ -0,0 +1,75 @@
+
+// Gawain element list (AKA index buffer)
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+#include "primitive.h"
+
+#define GWN_TRACK_INDEX_RANGE 1
+
+typedef enum {
+ GWN_INDEX_U8, // GL has this, Vulkan does not
+ GWN_INDEX_U16,
+ GWN_INDEX_U32
+} Gwn_IndexBufType;
+
+typedef struct {
+ unsigned index_ct;
+#if GWN_TRACK_INDEX_RANGE
+ Gwn_IndexBufType index_type;
+ GLenum gl_index_type;
+ unsigned min_index;
+ unsigned max_index;
+ unsigned base_index;
+#endif
+ void* data; // NULL indicates data in VRAM (unmapped) or not yet allocated
+ GLuint vbo_id; // 0 indicates not yet sent to VRAM
+} Gwn_IndexBuf;
+
+void GWN_indexbuf_use(Gwn_IndexBuf*);
+unsigned GWN_indexbuf_size_get(const Gwn_IndexBuf*);
+
+typedef struct {
+ unsigned max_allowed_index;
+ unsigned max_index_ct;
+ unsigned index_ct;
+ Gwn_PrimType prim_type;
+ unsigned* data;
+} Gwn_IndexBufBuilder;
+
+// supported primitives:
+// GWN_PRIM_POINTS
+// GWN_PRIM_LINES
+// GWN_PRIM_TRIS
+
+void GWN_indexbuf_init(Gwn_IndexBufBuilder*, Gwn_PrimType, unsigned prim_ct, unsigned vertex_ct);
+//void GWN_indexbuf_init_custom(Gwn_IndexBufBuilder*, Gwn_PrimType, unsigned index_ct, unsigned vertex_ct);
+
+void GWN_indexbuf_add_generic_vert(Gwn_IndexBufBuilder*, unsigned v);
+
+void GWN_indexbuf_add_point_vert(Gwn_IndexBufBuilder*, unsigned v);
+void GWN_indexbuf_add_line_verts(Gwn_IndexBufBuilder*, unsigned v1, unsigned v2);
+void GWN_indexbuf_add_tri_verts(Gwn_IndexBufBuilder*, unsigned v1, unsigned v2, unsigned v3);
+
+Gwn_IndexBuf* GWN_indexbuf_build(Gwn_IndexBufBuilder*);
+void GWN_indexbuf_build_in_place(Gwn_IndexBufBuilder*, Gwn_IndexBuf*);
+
+void GWN_indexbuf_discard(Gwn_IndexBuf*);
+
+
+/* Macros */
+
+#define GWN_INDEXBUF_DISCARD_SAFE(elem) do { \
+ if (elem != NULL) { \
+ GWN_indexbuf_discard(elem); \
+ elem = NULL; \
+ } \
+} while (0)
diff --git a/intern/gawain/gawain/imm_util.h b/intern/gawain/gawain/imm_util.h
new file mode 100644
index 00000000000..730bd7c1a3c
--- /dev/null
+++ b/intern/gawain/gawain/imm_util.h
@@ -0,0 +1,18 @@
+
+// Gawain immediate mode drawing utilities
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+
+// Draw 2D rectangles (replaces glRect functions)
+// caller is reponsible for vertex format & shader
+void immRectf(unsigned pos, float x1, float y1, float x2, float y2);
+void immRecti(unsigned pos, int x1, int y1, int x2, int y2);
diff --git a/intern/gawain/gawain/immediate.h b/intern/gawain/gawain/immediate.h
new file mode 100644
index 00000000000..39ba76db931
--- /dev/null
+++ b/intern/gawain/gawain/immediate.h
@@ -0,0 +1,119 @@
+
+// Gawain immediate mode work-alike
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+#include "vertex_format.h"
+#include "primitive.h"
+#include "shader_interface.h"
+
+#define IMM_BATCH_COMBO 1
+
+
+Gwn_VertFormat* immVertexFormat(void); // returns a cleared vertex format, ready for add_attrib
+
+void immBindProgram(GLuint program, const Gwn_ShaderInterface*); // every immBegin must have a program bound first
+void immUnbindProgram(void); // call after your last immEnd, or before binding another program
+
+void immBegin(Gwn_PrimType, unsigned vertex_ct); // must supply exactly vertex_ct vertices
+void immBeginAtMost(Gwn_PrimType, unsigned max_vertex_ct); // can supply fewer vertices
+void immEnd(void); // finishes and draws
+
+#if IMM_BATCH_COMBO
+#include "batch.h"
+// immBegin a batch, then use standard immFunctions as usual.
+// immEnd will finalize the batch instead of drawing.
+// Then you can draw it as many times as you like! Partially replaces the need for display lists.
+Gwn_Batch* immBeginBatch(Gwn_PrimType, unsigned vertex_ct);
+Gwn_Batch* immBeginBatchAtMost(Gwn_PrimType, unsigned vertex_ct);
+#endif
+
+
+// provide attribute values that can change per vertex
+// first vertex after immBegin must have all its attributes specified
+// skipped attributes will continue using the previous value for that attrib_id
+void immAttrib1f(unsigned attrib_id, float x);
+void immAttrib2f(unsigned attrib_id, float x, float y);
+void immAttrib3f(unsigned attrib_id, float x, float y, float z);
+void immAttrib4f(unsigned attrib_id, float x, float y, float z, float w);
+
+void immAttrib2i(unsigned attrib_id, int x, int y);
+
+void immAttrib1u(unsigned attrib_id, unsigned x);
+
+void immAttrib2s(unsigned attrib_id, short x, short y);
+
+void immAttrib2fv(unsigned attrib_id, const float data[2]);
+void immAttrib3fv(unsigned attrib_id, const float data[3]);
+void immAttrib4fv(unsigned attrib_id, const float data[4]);
+
+void immAttrib3ub(unsigned attrib_id, unsigned char r, unsigned char g, unsigned char b);
+void immAttrib4ub(unsigned attrib_id, unsigned char r, unsigned char g, unsigned char b, unsigned char a);
+
+void immAttrib3ubv(unsigned attrib_id, const unsigned char data[4]);
+void immAttrib4ubv(unsigned attrib_id, const unsigned char data[4]);
+
+// explicitly skip an attribute
+// this advanced option kills automatic value copying for this attrib_id
+void immSkipAttrib(unsigned attrib_id);
+
+
+// provide one last attribute value & end the current vertex
+// this is most often used for 2D or 3D position (similar to glVertex)
+void immVertex2f(unsigned attrib_id, float x, float y);
+void immVertex3f(unsigned attrib_id, float x, float y, float z);
+
+void immVertex2i(unsigned attrib_id, int x, int y);
+
+void immVertex2s(unsigned attrib_id, short x, short y);
+
+void immVertex2fv(unsigned attrib_id, const float data[2]);
+void immVertex3fv(unsigned attrib_id, const float data[3]);
+
+void immVertex2iv(unsigned attrib_id, const int data[2]);
+
+
+// provide uniform values that don't change for the entire draw call
+void immUniform1i(const char* name, int x);
+void immUniform4iv(const char* name, const int data[4]);
+void immUniform1f(const char* name, float x);
+void immUniform2f(const char* name, float x, float y);
+void immUniform2fv(const char* name, const float data[2]);
+void immUniform3f(const char* name, float x, float y, float z);
+void immUniform3fv(const char* name, const float data[3]);
+void immUniformArray3fv(const char* name, const float *data, int count);
+void immUniform4f(const char* name, float x, float y, float z, float w);
+void immUniform4fv(const char* name, const float data[4]);
+void immUniformArray4fv(const char* bare_name, const float *data, int count);
+void immUniformMatrix4fv(const char* name, const float data[4][4]);
+
+
+// convenience functions for setting "uniform vec4 color"
+// the rgb functions have implicit alpha = 1.0
+void immUniformColor4f(float r, float g, float b, float a);
+void immUniformColor4fv(const float rgba[4]);
+void immUniformColor3f(float r, float g, float b);
+void immUniformColor3fv(const float rgb[3]);
+void immUniformColor3fvAlpha(const float rgb[3], float a);
+
+void immUniformColor3ub(unsigned char r, unsigned char g, unsigned char b);
+void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
+void immUniformColor3ubv(const unsigned char rgb[3]);
+void immUniformColor3ubvAlpha(const unsigned char rgb[3], unsigned char a);
+void immUniformColor4ubv(const unsigned char rgba[4]);
+
+
+// these are called by the system -- not part of drawing API
+
+void immInit(void);
+void immActivate(void);
+void immDeactivate(void);
+void immDestroy(void);
diff --git a/intern/gawain/gawain/primitive.h b/intern/gawain/gawain/primitive.h
new file mode 100644
index 00000000000..c6786dc1993
--- /dev/null
+++ b/intern/gawain/gawain/primitive.h
@@ -0,0 +1,40 @@
+
+// Gawain geometric primitives
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2017 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+#include "common.h"
+
+typedef enum {
+ GWN_PRIM_POINTS,
+ GWN_PRIM_LINES,
+ GWN_PRIM_TRIS,
+ GWN_PRIM_LINE_STRIP,
+ GWN_PRIM_LINE_LOOP, // GL has this, Vulkan does not
+ GWN_PRIM_TRI_STRIP,
+ GWN_PRIM_TRI_FAN,
+
+ GWN_PRIM_LINE_STRIP_ADJ,
+
+ GWN_PRIM_NONE
+} Gwn_PrimType;
+
+// what types of primitives does each shader expect?
+typedef enum {
+ GWN_PRIM_CLASS_NONE = 0,
+ GWN_PRIM_CLASS_POINT = (1 << 0),
+ GWN_PRIM_CLASS_LINE = (1 << 1),
+ GWN_PRIM_CLASS_SURFACE = (1 << 2),
+ GWN_PRIM_CLASS_ANY = GWN_PRIM_CLASS_POINT | GWN_PRIM_CLASS_LINE | GWN_PRIM_CLASS_SURFACE
+} Gwn_PrimClass;
+
+Gwn_PrimClass GWN_primtype_class(Gwn_PrimType);
+bool GWN_primtype_belongs_to_class(Gwn_PrimType, Gwn_PrimClass);
diff --git a/intern/gawain/gawain/primitive_private.h b/intern/gawain/gawain/primitive_private.h
new file mode 100644
index 00000000000..d959cd89852
--- /dev/null
+++ b/intern/gawain/gawain/primitive_private.h
@@ -0,0 +1,14 @@
+
+// Gawain geometric primitives (private interface for use inside Gawain)
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2017 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+GLenum convert_prim_type_to_gl(Gwn_PrimType);
diff --git a/intern/gawain/gawain/shader_interface.h b/intern/gawain/gawain/shader_interface.h
new file mode 100644
index 00000000000..5304cc9fa51
--- /dev/null
+++ b/intern/gawain/gawain/shader_interface.h
@@ -0,0 +1,53 @@
+
+// Gawain shader interface (C --> GLSL)
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2017 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+#include "common.h"
+
+typedef enum {
+ GWN_UNIFORM_NONE, // uninitialized/unknown
+
+ GWN_UNIFORM_MODELVIEW, // mat4 ModelViewMatrix
+ GWN_UNIFORM_PROJECTION, // mat4 ProjectionMatrix
+ GWN_UNIFORM_MVP, // mat4 ModelViewProjectionMatrix
+
+ GWN_UNIFORM_MODELVIEW_INV, // mat4 ModelViewInverseMatrix
+ GWN_UNIFORM_PROJECTION_INV, // mat4 ProjectionInverseMatrix
+
+ GWN_UNIFORM_NORMAL, // mat3 NormalMatrix
+
+ GWN_UNIFORM_COLOR, // vec4 color
+
+ GWN_UNIFORM_CUSTOM // custom uniform, not one of the above built-ins
+} Gwn_UniformBuiltin;
+
+typedef struct {
+ const char* name;
+ unsigned name_hash;
+ GLenum gl_type;
+ Gwn_UniformBuiltin builtin_type; // only for uniform inputs
+ GLint size;
+ GLint location;
+} Gwn_ShaderInput;
+
+typedef struct {
+ uint16_t uniform_ct;
+ uint16_t attrib_ct;
+ Gwn_ShaderInput inputs[0]; // dynamic size, uniforms followed by attribs
+} Gwn_ShaderInterface;
+
+Gwn_ShaderInterface* GWN_shaderinterface_create(GLint program_id);
+void GWN_shaderinterface_discard(Gwn_ShaderInterface*);
+
+const Gwn_ShaderInput* GWN_shaderinterface_uniform(const Gwn_ShaderInterface*, const char* name);
+const Gwn_ShaderInput* GWN_shaderinterface_uniform_builtin(const Gwn_ShaderInterface*, Gwn_UniformBuiltin);
+const Gwn_ShaderInput* GWN_shaderinterface_attr(const Gwn_ShaderInterface*, const char* name);
diff --git a/intern/gawain/gawain/vertex_buffer.h b/intern/gawain/gawain/vertex_buffer.h
new file mode 100644
index 00000000000..9aee8e05877
--- /dev/null
+++ b/intern/gawain/gawain/vertex_buffer.h
@@ -0,0 +1,108 @@
+
+// Gawain vertex buffer
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+#include "vertex_format.h"
+
+// How to create a Gwn_VertBuf:
+// 1) verts = GWN_vertbuf_create() or GWN_vertbuf_init(verts)
+// 2) GWN_vertformat_attr_add(verts->format, ...)
+// 3) GWN_vertbuf_data_alloc(verts, vertex_ct) <-- finalizes/packs vertex format
+// 4) GWN_vertbuf_attr_fill(verts, pos, application_pos_buffer)
+
+// Is Gwn_VertBuf always used as part of a Gwn_Batch?
+
+typedef struct {
+ Gwn_VertFormat format;
+ unsigned vertex_ct;
+ GLubyte* data; // NULL indicates data in VRAM (unmapped) or not yet allocated
+ GLuint vbo_id; // 0 indicates not yet sent to VRAM
+} Gwn_VertBuf;
+
+Gwn_VertBuf* GWN_vertbuf_create(void);
+Gwn_VertBuf* GWN_vertbuf_create_with_format(const Gwn_VertFormat*);
+
+void GWN_vertbuf_clear(Gwn_VertBuf* verts);
+void GWN_vertbuf_discard(Gwn_VertBuf*);
+
+void GWN_vertbuf_init(Gwn_VertBuf*);
+void GWN_vertbuf_init_with_format(Gwn_VertBuf*, const Gwn_VertFormat*);
+
+unsigned GWN_vertbuf_size_get(const Gwn_VertBuf*);
+void GWN_vertbuf_data_alloc(Gwn_VertBuf*, unsigned v_ct);
+void GWN_vertbuf_data_resize(Gwn_VertBuf*, unsigned v_ct);
+
+// The most important set_attrib variant is the untyped one. Get it right first.
+// It takes a void* so the app developer is responsible for matching their app data types
+// to the vertex attribute's type and component count. They're in control of both, so this
+// should not be a problem.
+
+void GWN_vertbuf_attr_set(Gwn_VertBuf*, unsigned a_idx, unsigned v_idx, const void* data);
+void GWN_vertbuf_attr_fill(Gwn_VertBuf*, unsigned a_idx, const void* data); // tightly packed, non interleaved input data
+void GWN_vertbuf_attr_fill_stride(Gwn_VertBuf*, unsigned a_idx, unsigned stride, const void* data);
+
+// For low level access only
+typedef struct {
+ unsigned size;
+ unsigned stride;
+ GLubyte* data;
+ GLubyte* data_init;
+#if TRUST_NO_ONE
+ // Only for overflow check
+ GLubyte* _data_end;
+#endif
+} Gwn_VertBufRaw;
+
+GWN_INLINE void *GWN_vertbuf_raw_step(Gwn_VertBufRaw *a)
+ {
+ GLubyte* data = a->data;
+ a->data += a->stride;
+#if TRUST_NO_ONE
+ assert(data < a->_data_end);
+#endif
+ return (void *)data;
+ }
+
+GWN_INLINE unsigned GWN_vertbuf_raw_used(Gwn_VertBufRaw *a)
+ {
+ return ((a->data - a->data_init) / a->stride);
+ }
+
+void GWN_vertbuf_attr_get_raw_data(Gwn_VertBuf*, unsigned a_idx, Gwn_VertBufRaw *access);
+
+// TODO: decide whether to keep the functions below
+// doesn't immediate mode satisfy these needs?
+
+// void setAttrib1f(unsigned a_idx, unsigned v_idx, float x);
+// void setAttrib2f(unsigned a_idx, unsigned v_idx, float x, float y);
+// void setAttrib3f(unsigned a_idx, unsigned v_idx, float x, float y, float z);
+// void setAttrib4f(unsigned a_idx, unsigned v_idx, float x, float y, float z, float w);
+//
+// void setAttrib3ub(unsigned a_idx, unsigned v_idx, unsigned char r, unsigned char g, unsigned char b);
+// void setAttrib4ub(unsigned a_idx, unsigned v_idx, unsigned char r, unsigned char g, unsigned char b, unsigned char a);
+
+void GWN_vertbuf_use(Gwn_VertBuf*);
+
+
+// Metrics
+
+unsigned GWN_vertbuf_get_memory_usage(void);
+
+
+// Macros
+
+#define GWN_VERTBUF_DISCARD_SAFE(verts) do { \
+ if (verts != NULL) { \
+ GWN_vertbuf_discard(verts); \
+ verts = NULL; \
+ } \
+} while (0)
diff --git a/intern/gawain/gawain/vertex_format.h b/intern/gawain/gawain/vertex_format.h
new file mode 100644
index 00000000000..ab61722db60
--- /dev/null
+++ b/intern/gawain/gawain/vertex_format.h
@@ -0,0 +1,78 @@
+
+// Gawain vertex format
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+#include "common.h"
+
+#define GWN_VERT_ATTR_MAX_LEN 16
+#define MAX_ATTRIB_NAMES 3
+#define GWN_VERT_ATTR_NAME_AVERAGE_LEN 11
+#define GWN_VERT_ATTR_NAMES_BUF_LEN ((GWN_VERT_ATTR_NAME_AVERAGE_LEN + 1) * GWN_VERT_ATTR_MAX_LEN)
+
+typedef enum {
+ GWN_COMP_I8,
+ GWN_COMP_U8,
+ GWN_COMP_I16,
+ GWN_COMP_U16,
+ GWN_COMP_I32,
+ GWN_COMP_U32,
+
+ GWN_COMP_F32,
+
+ GWN_COMP_I10
+} Gwn_VertCompType;
+
+typedef enum {
+ GWN_FETCH_FLOAT,
+ GWN_FETCH_INT,
+ GWN_FETCH_INT_TO_FLOAT_UNIT, // 127 (ubyte) -> 0.5 (and so on for other int types)
+ GWN_FETCH_INT_TO_FLOAT // 127 (any int type) -> 127.0
+} Gwn_VertFetchMode;
+
+typedef struct {
+ Gwn_VertCompType comp_type;
+ unsigned gl_comp_type;
+ unsigned comp_ct; // 1 to 4
+ unsigned sz; // size in bytes, 1 to 16
+ unsigned offset; // from beginning of vertex, in bytes
+ Gwn_VertFetchMode fetch_mode;
+ const char* name[MAX_ATTRIB_NAMES];
+ unsigned name_ct;
+} Gwn_VertAttr;
+
+typedef struct {
+ unsigned attrib_ct; // 0 to 16 (GWN_VERT_ATTR_MAX_LEN)
+ unsigned name_ct; // total count of active vertex attrib
+ unsigned stride; // stride in bytes, 1 to 256
+ bool packed;
+ Gwn_VertAttr attribs[GWN_VERT_ATTR_MAX_LEN]; // TODO: variable-size attribs array
+ char names[GWN_VERT_ATTR_NAMES_BUF_LEN];
+ unsigned name_offset;
+} Gwn_VertFormat;
+
+void GWN_vertformat_clear(Gwn_VertFormat*);
+void GWN_vertformat_copy(Gwn_VertFormat* dest, const Gwn_VertFormat* src);
+
+unsigned GWN_vertformat_attr_add(Gwn_VertFormat*, const char* name, Gwn_VertCompType, unsigned comp_ct, Gwn_VertFetchMode);
+void GWN_vertformat_alias_add(Gwn_VertFormat*, const char* alias);
+
+// format conversion
+
+typedef struct {
+ int x : 10;
+ int y : 10;
+ int z : 10;
+ int w : 2; // 0 by default, can manually set to { -2, -1, 0, 1 }
+} Gwn_PackedNormal;
+
+Gwn_PackedNormal GWN_normal_convert_i10_v3(const float data[3]);
+Gwn_PackedNormal GWN_normal_convert_i10_s3(const short data[3]);
diff --git a/intern/gawain/gawain/vertex_format_private.h b/intern/gawain/gawain/vertex_format_private.h
new file mode 100644
index 00000000000..c1a0f734eda
--- /dev/null
+++ b/intern/gawain/gawain/vertex_format_private.h
@@ -0,0 +1,16 @@
+
+// Gawain vertex format (private interface for use inside Gawain)
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016-2017 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+void VertexFormat_pack(Gwn_VertFormat*);
+unsigned padding(unsigned offset, unsigned alignment);
+unsigned vertex_buffer_size(const Gwn_VertFormat*, unsigned vertex_ct);
diff --git a/intern/gawain/src/attrib_binding.c b/intern/gawain/src/attrib_binding.c
new file mode 100644
index 00000000000..6cdb8a0e542
--- /dev/null
+++ b/intern/gawain/src/attrib_binding.c
@@ -0,0 +1,70 @@
+
+// Gawain vertex attribute binding
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#include "attrib_binding.h"
+#include "attrib_binding_private.h"
+#include <stddef.h>
+
+#if GWN_VERT_ATTR_MAX_LEN != 16
+ #error "attrib binding code assumes GWN_VERT_ATTR_MAX_LEN = 16"
+#endif
+
+void AttribBinding_clear(Gwn_AttrBinding* binding)
+ {
+ binding->loc_bits = 0;
+ binding->enabled_bits = 0;
+ }
+
+unsigned read_attrib_location(const Gwn_AttrBinding* binding, unsigned a_idx)
+ {
+#if TRUST_NO_ONE
+ assert(a_idx < GWN_VERT_ATTR_MAX_LEN);
+ assert(binding->enabled_bits & (1 << a_idx));
+#endif
+
+ return (binding->loc_bits >> (4 * a_idx)) & 0xF;
+ }
+
+static void write_attrib_location(Gwn_AttrBinding* binding, unsigned a_idx, unsigned location)
+ {
+#if TRUST_NO_ONE
+ assert(a_idx < GWN_VERT_ATTR_MAX_LEN);
+ assert(location < GWN_VERT_ATTR_MAX_LEN);
+#endif
+
+ const unsigned shift = 4 * a_idx;
+ const uint64_t mask = ((uint64_t)0xF) << shift;
+ // overwrite this attrib's previous location
+ binding->loc_bits = (binding->loc_bits & ~mask) | (location << shift);
+ // mark this attrib as enabled
+ binding->enabled_bits |= 1 << a_idx;
+ }
+
+void get_attrib_locations(const Gwn_VertFormat* format, Gwn_AttrBinding* binding, const Gwn_ShaderInterface* shaderface)
+ {
+ AttribBinding_clear(binding);
+
+ for (unsigned a_idx = 0; a_idx < format->attrib_ct; ++a_idx)
+ {
+ const Gwn_VertAttr* a = format->attribs + a_idx;
+ for (unsigned n_idx = 0; n_idx < a->name_ct; ++n_idx)
+ {
+ const Gwn_ShaderInput* input = GWN_shaderinterface_attr(shaderface, a->name[n_idx]);
+
+#if TRUST_NO_ONE
+ assert(input != NULL);
+ // TODO: make this a recoverable runtime error? indicates mismatch between vertex format and program
+#endif
+
+ write_attrib_location(binding, a_idx, input->location);
+ }
+ }
+ }
diff --git a/intern/gawain/src/batch.c b/intern/gawain/src/batch.c
new file mode 100644
index 00000000000..22a5aab48b4
--- /dev/null
+++ b/intern/gawain/src/batch.c
@@ -0,0 +1,449 @@
+
+// Gawain geometry batch
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#include "batch.h"
+#include "buffer_id.h"
+#include "primitive_private.h"
+#include <stdlib.h>
+
+// necessary functions from matrix API
+extern void gpuBindMatrices(const Gwn_ShaderInterface* shaderface);
+extern bool gpuMatricesDirty(void); // how best to use this here?
+
+Gwn_Batch* GWN_batch_create(Gwn_PrimType prim_type, Gwn_VertBuf* verts, Gwn_IndexBuf* elem)
+ {
+ Gwn_Batch* batch = calloc(1, sizeof(Gwn_Batch));
+
+ GWN_batch_init(batch, prim_type, verts, elem);
+
+ return batch;
+ }
+
+void GWN_batch_init(Gwn_Batch* batch, Gwn_PrimType prim_type, Gwn_VertBuf* verts, Gwn_IndexBuf* elem)
+ {
+#if TRUST_NO_ONE
+ assert(verts != NULL);
+#endif
+
+ batch->verts[0] = verts;
+ for (int v = 1; v < GWN_BATCH_VBO_MAX_LEN; ++v)
+ batch->verts[v] = NULL;
+ batch->elem = elem;
+ batch->prim_type = prim_type;
+ batch->gl_prim_type = convert_prim_type_to_gl(prim_type);
+ batch->phase = GWN_BATCH_READY_TO_DRAW;
+ }
+
+void GWN_batch_discard(Gwn_Batch* batch)
+ {
+ if (batch->vao_id)
+ GWN_vao_free(batch->vao_id);
+
+ free(batch);
+ }
+
+void GWN_batch_discard_all(Gwn_Batch* batch)
+ {
+ for (int v = 0; v < GWN_BATCH_VBO_MAX_LEN; ++v)
+ {
+ if (batch->verts[v] == NULL)
+ break;
+ GWN_vertbuf_discard(batch->verts[v]);
+ }
+
+ if (batch->elem)
+ GWN_indexbuf_discard(batch->elem);
+
+ GWN_batch_discard(batch);
+ }
+
+int GWN_batch_vertbuf_add(Gwn_Batch* batch, Gwn_VertBuf* verts)
+ {
+ for (unsigned v = 0; v < GWN_BATCH_VBO_MAX_LEN; ++v)
+ {
+ if (batch->verts[v] == NULL)
+ {
+#if TRUST_NO_ONE
+ // for now all VertexBuffers must have same vertex_ct
+ assert(verts->vertex_ct == batch->verts[0]->vertex_ct);
+ // in the near future we will enable instanced attribs which have their own vertex_ct
+#endif
+ batch->verts[v] = verts;
+ // TODO: mark dirty so we can keep attrib bindings up-to-date
+ return v;
+ }
+ }
+
+ // we only make it this far if there is no room for another Gwn_VertBuf
+#if TRUST_NO_ONE
+ assert(false);
+#endif
+ return -1;
+ }
+
+void GWN_batch_program_set(Gwn_Batch* batch, GLuint program, const Gwn_ShaderInterface* shaderface)
+ {
+#if TRUST_NO_ONE
+ assert(glIsProgram(program));
+#endif
+
+ batch->program = program;
+ batch->interface = shaderface;
+ batch->program_dirty = true;
+
+ GWN_batch_program_use_begin(batch); // hack! to make Batch_Uniform* simpler
+ }
+
+static void Batch_update_program_bindings(Gwn_Batch* batch)
+ {
+ // disable all as a precaution
+ // why are we not using prev_attrib_enabled_bits?? see immediate.c
+ for (unsigned a_idx = 0; a_idx < GWN_VERT_ATTR_MAX_LEN; ++a_idx)
+ glDisableVertexAttribArray(a_idx);
+
+ for (int v = 0; v < GWN_BATCH_VBO_MAX_LEN; ++v)
+ {
+ Gwn_VertBuf* verts = batch->verts[v];
+ if (verts == NULL)
+ break;
+
+ const Gwn_VertFormat* format = &verts->format;
+
+ const unsigned attrib_ct = format->attrib_ct;
+ const unsigned stride = format->stride;
+
+ GWN_vertbuf_use(verts);
+
+ for (unsigned a_idx = 0; a_idx < attrib_ct; ++a_idx)
+ {
+ const Gwn_VertAttr* a = format->attribs + a_idx;
+
+ const GLvoid* pointer = (const GLubyte*)0 + a->offset;
+
+ for (unsigned n_idx = 0; n_idx < a->name_ct; ++n_idx)
+ {
+ const Gwn_ShaderInput* input = GWN_shaderinterface_attr(batch->interface, a->name[n_idx]);
+
+ if (input == NULL) continue;
+
+ glEnableVertexAttribArray(input->location);
+
+ switch (a->fetch_mode)
+ {
+ case GWN_FETCH_FLOAT:
+ case GWN_FETCH_INT_TO_FLOAT:
+ glVertexAttribPointer(input->location, a->comp_ct, a->gl_comp_type, GL_FALSE, stride, pointer);
+ break;
+ case GWN_FETCH_INT_TO_FLOAT_UNIT:
+ glVertexAttribPointer(input->location, a->comp_ct, a->gl_comp_type, GL_TRUE, stride, pointer);
+ break;
+ case GWN_FETCH_INT:
+ glVertexAttribIPointer(input->location, a->comp_ct, a->gl_comp_type, stride, pointer);
+ }
+ }
+ }
+ }
+
+ batch->program_dirty = false;
+ }
+
+void GWN_batch_program_use_begin(Gwn_Batch* batch)
+ {
+ // NOTE: use_program & done_using_program are fragile, depend on staying in sync with
+ // the GL context's active program. use_program doesn't mark other programs as "not used".
+ // TODO: make not fragile (somehow)
+
+ if (!batch->program_in_use)
+ {
+ glUseProgram(batch->program);
+ batch->program_in_use = true;
+ }
+ }
+
+void GWN_batch_program_use_end(Gwn_Batch* batch)
+ {
+ if (batch->program_in_use)
+ {
+ glUseProgram(0);
+ batch->program_in_use = false;
+ }
+ }
+
+#if TRUST_NO_ONE
+ #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(batch->interface, name); assert(uniform);
+#else
+ #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(batch->interface, name);
+#endif
+
+void GWN_batch_uniform_1i(Gwn_Batch* batch, const char* name, int value)
+ {
+ GET_UNIFORM
+ glUniform1i(uniform->location, value);
+ }
+
+void GWN_batch_uniform_1b(Gwn_Batch* batch, const char* name, bool value)
+ {
+ GET_UNIFORM
+ glUniform1i(uniform->location, value ? GL_TRUE : GL_FALSE);
+ }
+
+void GWN_batch_uniform_2f(Gwn_Batch* batch, const char* name, float x, float y)
+ {
+ GET_UNIFORM
+ glUniform2f(uniform->location, x, y);
+ }
+
+void GWN_batch_uniform_3f(Gwn_Batch* batch, const char* name, float x, float y, float z)
+ {
+ GET_UNIFORM
+ glUniform3f(uniform->location, x, y, z);
+ }
+
+void GWN_batch_uniform_4f(Gwn_Batch* batch, const char* name, float x, float y, float z, float w)
+ {
+ GET_UNIFORM
+ glUniform4f(uniform->location, x, y, z, w);
+ }
+
+void GWN_batch_uniform_1f(Gwn_Batch* batch, const char* name, float x)
+ {
+ GET_UNIFORM
+ glUniform1f(uniform->location, x);
+ }
+
+void GWN_batch_uniform_3fv(Gwn_Batch* batch, const char* name, const float data[3])
+ {
+ GET_UNIFORM
+ glUniform3fv(uniform->location, 1, data);
+ }
+
+void GWN_batch_uniform_4fv(Gwn_Batch* batch, const char* name, const float data[4])
+ {
+ GET_UNIFORM
+ glUniform4fv(uniform->location, 1, data);
+ }
+
+static void Batch_prime(Gwn_Batch* batch)
+ {
+ batch->vao_id = GWN_vao_alloc();
+ glBindVertexArray(batch->vao_id);
+
+ for (int v = 0; v < GWN_BATCH_VBO_MAX_LEN; ++v)
+ {
+ if (batch->verts[v] == NULL)
+ break;
+ GWN_vertbuf_use(batch->verts[v]);
+ }
+
+ if (batch->elem)
+ GWN_indexbuf_use(batch->elem);
+
+ // vertex attribs and element list remain bound to this VAO
+ }
+
+void GWN_batch_draw(Gwn_Batch* batch)
+ {
+#if TRUST_NO_ONE
+ assert(batch->phase == GWN_BATCH_READY_TO_DRAW);
+ assert(glIsProgram(batch->program));
+#endif
+
+ if (batch->vao_id)
+ glBindVertexArray(batch->vao_id);
+ else
+ Batch_prime(batch);
+
+ if (batch->program_dirty)
+ Batch_update_program_bindings(batch);
+
+ GWN_batch_program_use_begin(batch);
+
+ gpuBindMatrices(batch->interface);
+
+ if (batch->elem)
+ {
+ const Gwn_IndexBuf* el = batch->elem;
+
+#if GWN_TRACK_INDEX_RANGE
+ if (el->base_index)
+ glDrawRangeElementsBaseVertex(batch->gl_prim_type, el->min_index, el->max_index, el->index_ct, el->gl_index_type, 0, el->base_index);
+ else
+ glDrawRangeElements(batch->gl_prim_type, el->min_index, el->max_index, el->index_ct, el->gl_index_type, 0);
+#else
+ glDrawElements(batch->gl_prim_type, el->index_ct, GL_UNSIGNED_INT, 0);
+#endif
+ }
+ else
+ glDrawArrays(batch->gl_prim_type, 0, batch->verts[0]->vertex_ct);
+
+ GWN_batch_program_use_end(batch);
+ glBindVertexArray(0);
+ }
+
+
+
+// clement : temp stuff
+void GWN_batch_draw_stupid(Gwn_Batch* batch)
+ {
+ if (batch->vao_id)
+ glBindVertexArray(batch->vao_id);
+ else
+ Batch_prime(batch);
+
+ if (batch->program_dirty)
+ Batch_update_program_bindings(batch);
+
+ // GWN_batch_program_use_begin(batch);
+
+ //gpuBindMatrices(batch->program);
+
+ if (batch->elem)
+ {
+ const Gwn_IndexBuf* el = batch->elem;
+
+#if GWN_TRACK_INDEX_RANGE
+ if (el->base_index)
+ glDrawRangeElementsBaseVertex(batch->gl_prim_type, el->min_index, el->max_index, el->index_ct, el->gl_index_type, 0, el->base_index);
+ else
+ glDrawRangeElements(batch->gl_prim_type, el->min_index, el->max_index, el->index_ct, el->gl_index_type, 0);
+#else
+ glDrawElements(batch->gl_prim_type, el->index_ct, GL_UNSIGNED_INT, 0);
+#endif
+ }
+ else
+ glDrawArrays(batch->gl_prim_type, 0, batch->verts[0]->vertex_ct);
+
+ // GWN_batch_program_use_end(batch);
+ glBindVertexArray(0);
+ }
+
+// clement : temp stuff
+void GWN_batch_draw_stupid_instanced(Gwn_Batch* batch, unsigned int instance_vbo, int instance_count,
+ int attrib_nbr, int attrib_stride, int attrib_size[16], int attrib_loc[16])
+ {
+ if (batch->vao_id)
+ glBindVertexArray(batch->vao_id);
+ else
+ Batch_prime(batch);
+
+ if (batch->program_dirty)
+ Batch_update_program_bindings(batch);
+
+ glBindBuffer(GL_ARRAY_BUFFER, instance_vbo);
+ int ptr_ofs = 0;
+ for (int i = 0; i < attrib_nbr; ++i)
+ {
+ int size = attrib_size[i];
+ int loc = attrib_loc[i];
+ int atr_ofs = 0;
+
+ while (size > 0)
+ {
+ glEnableVertexAttribArray(loc + atr_ofs);
+ glVertexAttribPointer(loc + atr_ofs, (size > 4) ? 4 : size, GL_FLOAT, GL_FALSE,
+ sizeof(float) * attrib_stride, (GLvoid*)(sizeof(float) * ptr_ofs));
+ glVertexAttribDivisor(loc + atr_ofs, 1);
+ atr_ofs++;
+ ptr_ofs += (size > 4) ? 4 : size;
+ size -= 4;
+ }
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ // GWN_batch_program_use_begin(batch);
+
+ //gpuBindMatrices(batch->program);
+
+ if (batch->elem)
+ {
+ const Gwn_IndexBuf* el = batch->elem;
+#if GWN_TRACK_INDEX_RANGE
+ glDrawElementsInstancedBaseVertex(batch->gl_prim_type, el->index_ct, el->gl_index_type, 0, instance_count, el->base_index);
+#else
+ glDrawElementsInstanced(batch->gl_prim_type, el->index_ct, GL_UNSIGNED_INT, 0, instance_count);
+#endif
+ }
+ else
+ glDrawArraysInstanced(batch->gl_prim_type, 0, batch->verts[0]->vertex_ct, instance_count);
+
+ // GWN_batch_program_use_end(batch);
+ glBindVertexArray(0);
+ }
+
+void GWN_batch_draw_stupid_instanced_with_batch(Gwn_Batch* batch_instanced, Gwn_Batch* batch_instancing)
+ {
+ if (batch_instanced->vao_id)
+ glBindVertexArray(batch_instanced->vao_id);
+ else
+ Batch_prime(batch_instanced);
+
+ if (batch_instanced->program_dirty)
+ Batch_update_program_bindings(batch_instanced);
+
+ Gwn_VertBuf* verts = batch_instancing->verts[0];
+
+ const Gwn_VertFormat* format = &verts->format;
+
+ const unsigned attrib_ct = format->attrib_ct;
+ const unsigned stride = format->stride;
+
+ GWN_vertbuf_use(verts);
+
+ for (unsigned a_idx = 0; a_idx < attrib_ct; ++a_idx)
+ {
+ const Gwn_VertAttr* a = format->attribs + a_idx;
+
+ const GLvoid* pointer = (const GLubyte*)0 + a->offset;
+
+ for (unsigned n_idx = 0; n_idx < a->name_ct; ++n_idx)
+ {
+ const Gwn_ShaderInput* input = GWN_shaderinterface_attr(batch_instanced->interface, a->name[n_idx]);
+
+ if (input == NULL) continue;
+
+ glEnableVertexAttribArray(input->location);
+ glVertexAttribDivisor(input->location, 1);
+
+ switch (a->fetch_mode)
+ {
+ case GWN_FETCH_FLOAT:
+ case GWN_FETCH_INT_TO_FLOAT:
+ glVertexAttribPointer(input->location, a->comp_ct, a->gl_comp_type, GL_FALSE, stride, pointer);
+ break;
+ case GWN_FETCH_INT_TO_FLOAT_UNIT:
+ glVertexAttribPointer(input->location, a->comp_ct, a->gl_comp_type, GL_TRUE, stride, pointer);
+ break;
+ case GWN_FETCH_INT:
+ glVertexAttribIPointer(input->location, a->comp_ct, a->gl_comp_type, stride, pointer);
+ }
+ }
+ }
+
+ // GWN_batch_program_use_begin(batch);
+
+ //gpuBindMatrices(batch->program);
+
+ if (batch_instanced->elem)
+ {
+ const Gwn_IndexBuf* el = batch_instanced->elem;
+
+#if GWN_TRACK_INDEX_RANGE
+ glDrawElementsInstancedBaseVertex(batch_instanced->gl_prim_type, el->index_ct, el->gl_index_type, 0, verts->vertex_ct, el->base_index);
+#else
+ glDrawElementsInstanced(batch_instanced->gl_prim_type, el->index_ct, GL_UNSIGNED_INT, 0, verts->vertex_ct);
+#endif
+ }
+ else
+ glDrawArraysInstanced(batch_instanced->gl_prim_type, 0, batch_instanced->verts[0]->vertex_ct, verts->vertex_ct);
+
+ // GWN_batch_program_use_end(batch);
+ glBindVertexArray(0);
+ } \ No newline at end of file
diff --git a/intern/gawain/src/buffer_id.cpp b/intern/gawain/src/buffer_id.cpp
new file mode 100644
index 00000000000..59a6b9c89e7
--- /dev/null
+++ b/intern/gawain/src/buffer_id.cpp
@@ -0,0 +1,115 @@
+
+// Gawain buffer IDs
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.#include "buffer_id.h"
+
+#include "buffer_id.h"
+#include <mutex>
+#include <vector>
+
+#define ORPHAN_DEBUG 0
+
+#if ORPHAN_DEBUG
+ #include <cstdio>
+#endif
+
+static std::vector<GLuint> orphaned_buffer_ids;
+static std::vector<GLuint> orphaned_vao_ids;
+
+static std::mutex orphan_mutex;
+
+extern "C" {
+extern int BLI_thread_is_main(void); // Blender-specific function
+}
+
+static bool thread_is_main()
+ {
+ // "main" here means the GL context's thread
+ return BLI_thread_is_main();
+ }
+
+GLuint GWN_buf_id_alloc()
+ {
+#if TRUST_NO_ONE
+ assert(thread_is_main());
+#endif
+
+ // delete orphaned IDs
+ orphan_mutex.lock();
+ if (!orphaned_buffer_ids.empty())
+ {
+ const auto orphaned_buffer_ct = (unsigned)orphaned_buffer_ids.size();
+#if ORPHAN_DEBUG
+ printf("deleting %u orphaned VBO%s\n", orphaned_buffer_ct, orphaned_buffer_ct == 1 ? "" : "s");
+#endif
+ glDeleteBuffers(orphaned_buffer_ct, orphaned_buffer_ids.data());
+ orphaned_buffer_ids.clear();
+ }
+ orphan_mutex.unlock();
+
+ GLuint new_buffer_id = 0;
+ glGenBuffers(1, &new_buffer_id);
+ return new_buffer_id;
+ }
+
+void GWN_buf_id_free(GLuint buffer_id)
+ {
+ if (thread_is_main())
+ glDeleteBuffers(1, &buffer_id);
+ else
+ {
+ // add this ID to the orphaned list
+ orphan_mutex.lock();
+#if ORPHAN_DEBUG
+ printf("orphaning VBO %u\n", buffer_id);
+#endif
+ orphaned_buffer_ids.emplace_back(buffer_id);
+ orphan_mutex.unlock();
+ }
+ }
+
+GLuint GWN_vao_alloc()
+ {
+#if TRUST_NO_ONE
+ assert(thread_is_main());
+#endif
+
+ // delete orphaned IDs
+ orphan_mutex.lock();
+ if (!orphaned_vao_ids.empty())
+ {
+ const auto orphaned_vao_ct = (unsigned)orphaned_vao_ids.size();
+#if ORPHAN_DEBUG
+ printf("deleting %u orphaned VAO%s\n", orphaned_vao_ct, orphaned_vao_ct == 1 ? "" : "s");
+#endif
+ glDeleteVertexArrays(orphaned_vao_ct, orphaned_vao_ids.data());
+ orphaned_vao_ids.clear();
+ }
+ orphan_mutex.unlock();
+
+ GLuint new_vao_id = 0;
+ glGenVertexArrays(1, &new_vao_id);
+ return new_vao_id;
+ }
+
+void GWN_vao_free(GLuint vao_id)
+ {
+ if (thread_is_main())
+ glDeleteVertexArrays(1, &vao_id);
+ else
+ {
+ // add this ID to the orphaned list
+ orphan_mutex.lock();
+#if ORPHAN_DEBUG
+ printf("orphaning VAO %u\n", vao_id);
+#endif
+ orphaned_vao_ids.emplace_back(vao_id);
+ orphan_mutex.unlock();
+ }
+ }
diff --git a/intern/gawain/src/element.c b/intern/gawain/src/element.c
new file mode 100644
index 00000000000..ecf555fbfe8
--- /dev/null
+++ b/intern/gawain/src/element.c
@@ -0,0 +1,295 @@
+
+// Gawain element list (AKA index buffer)
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#include "element.h"
+#include "buffer_id.h"
+#include <stdlib.h>
+
+#define KEEP_SINGLE_COPY 1
+
+static GLenum convert_index_type_to_gl(Gwn_IndexBufType type)
+ {
+ static const GLenum table[] = {
+ [GWN_INDEX_U8] = GL_UNSIGNED_BYTE, // GL has this, Vulkan does not
+ [GWN_INDEX_U16] = GL_UNSIGNED_SHORT,
+ [GWN_INDEX_U32] = GL_UNSIGNED_INT
+ };
+ return table[type];
+ }
+
+unsigned GWN_indexbuf_size_get(const Gwn_IndexBuf* elem)
+ {
+#if GWN_TRACK_INDEX_RANGE
+ static const unsigned table[] = {
+ [GWN_INDEX_U8] = sizeof(GLubyte), // GL has this, Vulkan does not
+ [GWN_INDEX_U16] = sizeof(GLushort),
+ [GWN_INDEX_U32] = sizeof(GLuint)
+ };
+ return elem->index_ct * table[elem->index_type];
+#else
+ return elem->index_ct * sizeof(GLuint);
+#endif
+ }
+
+static void ElementList_prime(Gwn_IndexBuf* elem)
+ {
+ elem->vbo_id = GWN_buf_id_alloc();
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id);
+ // fill with delicious data & send to GPU the first time only
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, GWN_indexbuf_size_get(elem), elem->data, GL_STATIC_DRAW);
+
+#if KEEP_SINGLE_COPY
+ // now that GL has a copy, discard original
+ free(elem->data);
+ elem->data = NULL;
+#endif
+ }
+
+void GWN_indexbuf_use(Gwn_IndexBuf* elem)
+ {
+ if (elem->vbo_id)
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id);
+ else
+ ElementList_prime(elem);
+ }
+
+void GWN_indexbuf_init(Gwn_IndexBufBuilder* builder, Gwn_PrimType prim_type, unsigned prim_ct, unsigned vertex_ct)
+ {
+ unsigned verts_per_prim = 0;
+ switch (prim_type)
+ {
+ case GWN_PRIM_POINTS:
+ verts_per_prim = 1;
+ break;
+ case GWN_PRIM_LINES:
+ verts_per_prim = 2;
+ break;
+ case GWN_PRIM_TRIS:
+ verts_per_prim = 3;
+ break;
+ default:
+#if TRUST_NO_ONE
+ assert(false);
+#endif
+ return;
+ }
+
+ builder->max_allowed_index = vertex_ct - 1;
+ builder->max_index_ct = prim_ct * verts_per_prim;
+ builder->index_ct = 0; // start empty
+ builder->prim_type = prim_type;
+ builder->data = calloc(builder->max_index_ct, sizeof(unsigned));
+ }
+
+void GWN_indexbuf_add_generic_vert(Gwn_IndexBufBuilder* builder, unsigned v)
+ {
+#if TRUST_NO_ONE
+ assert(builder->data != NULL);
+ assert(builder->index_ct < builder->max_index_ct);
+ assert(v <= builder->max_allowed_index);
+#endif
+
+ builder->data[builder->index_ct++] = v;
+ }
+
+void GWN_indexbuf_add_point_vert(Gwn_IndexBufBuilder* builder, unsigned v)
+ {
+#if TRUST_NO_ONE
+ assert(builder->prim_type == GWN_PRIM_POINTS);
+#endif
+
+ GWN_indexbuf_add_generic_vert(builder, v);
+ }
+
+void GWN_indexbuf_add_line_verts(Gwn_IndexBufBuilder* builder, unsigned v1, unsigned v2)
+ {
+#if TRUST_NO_ONE
+ assert(builder->prim_type == GWN_PRIM_LINES);
+ assert(v1 != v2);
+#endif
+
+ GWN_indexbuf_add_generic_vert(builder, v1);
+ GWN_indexbuf_add_generic_vert(builder, v2);
+ }
+
+void GWN_indexbuf_add_tri_verts(Gwn_IndexBufBuilder* builder, unsigned v1, unsigned v2, unsigned v3)
+ {
+#if TRUST_NO_ONE
+ assert(builder->prim_type == GWN_PRIM_TRIS);
+ assert(v1 != v2 && v2 != v3 && v3 != v1);
+#endif
+
+ GWN_indexbuf_add_generic_vert(builder, v1);
+ GWN_indexbuf_add_generic_vert(builder, v2);
+ GWN_indexbuf_add_generic_vert(builder, v3);
+ }
+
+#if GWN_TRACK_INDEX_RANGE
+// Everything remains 32 bit while building to keep things simple.
+// Find min/max after, then convert to smallest index type possible.
+
+static unsigned index_range(const unsigned values[], unsigned value_ct, unsigned* min_out, unsigned* max_out)
+ {
+ if (value_ct == 0)
+ {
+ *min_out = 0;
+ *max_out = 0;
+ return 0;
+ }
+ unsigned min_value = values[0];
+ unsigned max_value = values[0];
+ for (unsigned i = 1; i < value_ct; ++i)
+ {
+ const unsigned value = values[i];
+ if (value < min_value)
+ min_value = value;
+ else if (value > max_value)
+ max_value = value;
+ }
+ *min_out = min_value;
+ *max_out = max_value;
+ return max_value - min_value;
+ }
+
+static void squeeze_indices_byte(const unsigned values[], Gwn_IndexBuf* elem)
+ {
+ const unsigned index_ct = elem->index_ct;
+ GLubyte* data = malloc(index_ct * sizeof(GLubyte));
+
+ if (elem->max_index > 0xFF)
+ {
+ const unsigned base = elem->min_index;
+
+ elem->base_index = base;
+ elem->min_index = 0;
+ elem->max_index -= base;
+
+ for (unsigned i = 0; i < index_ct; ++i)
+ data[i] = (GLubyte)(values[i] - base);
+ }
+ else
+ {
+ elem->base_index = 0;
+
+ for (unsigned i = 0; i < index_ct; ++i)
+ data[i] = (GLubyte)(values[i]);
+ }
+
+ elem->data = data;
+ }
+
+static void squeeze_indices_short(const unsigned values[], Gwn_IndexBuf* elem)
+ {
+ const unsigned index_ct = elem->index_ct;
+ GLushort* data = malloc(index_ct * sizeof(GLushort));
+
+ if (elem->max_index > 0xFFFF)
+ {
+ const unsigned base = elem->min_index;
+
+ elem->base_index = base;
+ elem->min_index = 0;
+ elem->max_index -= base;
+
+ for (unsigned i = 0; i < index_ct; ++i)
+ data[i] = (GLushort)(values[i] - base);
+ }
+ else
+ {
+ elem->base_index = 0;
+
+ for (unsigned i = 0; i < index_ct; ++i)
+ data[i] = (GLushort)(values[i]);
+ }
+
+ elem->data = data;
+ }
+
+#endif // GWN_TRACK_INDEX_RANGE
+
+Gwn_IndexBuf* GWN_indexbuf_build(Gwn_IndexBufBuilder* builder)
+ {
+ Gwn_IndexBuf* elem = calloc(1, sizeof(Gwn_IndexBuf));
+ GWN_indexbuf_build_in_place(builder, elem);
+ return elem;
+ }
+
+void GWN_indexbuf_build_in_place(Gwn_IndexBufBuilder* builder, Gwn_IndexBuf* elem)
+ {
+#if TRUST_NO_ONE
+ assert(builder->data != NULL);
+#endif
+
+ elem->index_ct = builder->index_ct;
+
+#if GWN_TRACK_INDEX_RANGE
+ const unsigned range = index_range(builder->data, builder->index_ct, &elem->min_index, &elem->max_index);
+
+ if (range <= 0xFF)
+ {
+ elem->index_type = GWN_INDEX_U8;
+ squeeze_indices_byte(builder->data, elem);
+ }
+ else if (range <= 0xFFFF)
+ {
+ elem->index_type = GWN_INDEX_U16;
+ squeeze_indices_short(builder->data, elem);
+ }
+ else
+ {
+ elem->index_type = GWN_INDEX_U32;
+ elem->base_index = 0;
+
+ if (builder->index_ct < builder->max_index_ct)
+ {
+ builder->data = realloc(builder->data, builder->index_ct * sizeof(unsigned));
+ // TODO: realloc only if index_ct is much smaller than max_index_ct
+ }
+
+ elem->data = builder->data;
+ }
+
+ elem->gl_index_type = convert_index_type_to_gl(elem->index_type);
+#else
+ if (builder->index_ct < builder->max_index_ct)
+ {
+ builder->data = realloc(builder->data, builder->index_ct * sizeof(unsigned));
+ // TODO: realloc only if index_ct is much smaller than max_index_ct
+ }
+
+ elem->data = builder->data;
+#endif
+
+ // elem->data will never be *larger* than builder->data... how about converting
+ // in place to avoid extra allocation?
+
+ elem->vbo_id = 0;
+ // TODO: create GL buffer object directly, based on an input flag
+
+ // discard builder (one-time use)
+ if (builder->data != elem->data)
+ free(builder->data);
+ builder->data = NULL;
+ // other fields are safe to leave
+ }
+
+void GWN_indexbuf_discard(Gwn_IndexBuf* elem)
+ {
+ if (elem->vbo_id)
+ GWN_buf_id_free(elem->vbo_id);
+#if KEEP_SINGLE_COPY
+ else
+#endif
+ if (elem->data)
+ free(elem->data);
+
+ free(elem);
+ }
diff --git a/intern/gawain/src/imm_util.c b/intern/gawain/src/imm_util.c
new file mode 100644
index 00000000000..b06778c9045
--- /dev/null
+++ b/intern/gawain/src/imm_util.c
@@ -0,0 +1,46 @@
+
+// Gawain immediate mode drawing utilities
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#include "imm_util.h"
+#include "immediate.h"
+
+
+void immRectf(unsigned pos, float x1, float y1, float x2, float y2)
+ {
+ immBegin(GWN_PRIM_TRI_FAN, 4);
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x2, y1);
+ immVertex2f(pos, x2, y2);
+ immVertex2f(pos, x1, y2);
+ immEnd();
+ }
+
+void immRecti(unsigned pos, int x1, int y1, int x2, int y2)
+ {
+ immBegin(GWN_PRIM_TRI_FAN, 4);
+ immVertex2i(pos, x1, y1);
+ immVertex2i(pos, x2, y1);
+ immVertex2i(pos, x2, y2);
+ immVertex2i(pos, x1, y2);
+ immEnd();
+ }
+
+#if 0 // more complete version in case we want that
+void immRecti_complete(int x1, int y1, int x2, int y2, const float color[4])
+ {
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned pos = add_attrib(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4fv(color);
+ immRecti(pos, x1, y1, x2, y2);
+ immUnbindProgram();
+ }
+#endif
diff --git a/intern/gawain/src/immediate.c b/intern/gawain/src/immediate.c
new file mode 100644
index 00000000000..5eb5ebb8336
--- /dev/null
+++ b/intern/gawain/src/immediate.c
@@ -0,0 +1,919 @@
+
+// Gawain immediate mode work-alike
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#include "immediate.h"
+#include "buffer_id.h"
+#include "attrib_binding.h"
+#include "attrib_binding_private.h"
+#include "vertex_format_private.h"
+#include "primitive_private.h"
+#include <string.h>
+
+// necessary functions from matrix API
+extern void gpuBindMatrices(const Gwn_ShaderInterface*);
+extern bool gpuMatricesDirty(void);
+
+typedef struct {
+ // TODO: organize this struct by frequency of change (run-time)
+
+#if IMM_BATCH_COMBO
+ Gwn_Batch* batch;
+#endif
+
+ // current draw call
+ GLubyte* buffer_data;
+ unsigned buffer_offset;
+ unsigned buffer_bytes_mapped;
+ unsigned vertex_ct;
+ bool strict_vertex_ct;
+ Gwn_PrimType prim_type;
+
+ Gwn_VertFormat vertex_format;
+
+ // current vertex
+ unsigned vertex_idx;
+ GLubyte* vertex_data;
+ uint16_t unassigned_attrib_bits; // which attributes of current vertex have not been given values?
+
+ GLuint vbo_id;
+ GLuint vao_id;
+
+ GLuint bound_program;
+ const Gwn_ShaderInterface* shader_interface;
+ Gwn_AttrBinding attrib_binding;
+ uint16_t prev_enabled_attrib_bits; // <-- only affects this VAO, so we're ok
+} Immediate;
+
+// size of internal buffer -- make this adjustable?
+#define IMM_BUFFER_SIZE (4 * 1024 * 1024)
+
+static bool initialized = false;
+static Immediate imm;
+
+void immInit(void)
+ {
+#if TRUST_NO_ONE
+ assert(!initialized);
+#endif
+
+ memset(&imm, 0, sizeof(Immediate));
+
+ imm.vbo_id = GWN_buf_id_alloc();
+ glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id);
+ glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW);
+
+ imm.prim_type = GWN_PRIM_NONE;
+ imm.strict_vertex_ct = true;
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ initialized = true;
+
+ immActivate();
+ }
+
+void immActivate(void)
+ {
+#if TRUST_NO_ONE
+ assert(initialized);
+ assert(imm.prim_type == GWN_PRIM_NONE); // make sure we're not between a Begin/End pair
+ assert(imm.vao_id == 0);
+#endif
+
+ imm.vao_id = GWN_vao_alloc();
+ }
+
+void immDeactivate(void)
+ {
+#if TRUST_NO_ONE
+ assert(initialized);
+ assert(imm.prim_type == GWN_PRIM_NONE); // make sure we're not between a Begin/End pair
+ assert(imm.vao_id != 0);
+#endif
+
+ GWN_vao_free(imm.vao_id);
+ imm.vao_id = 0;
+ imm.prev_enabled_attrib_bits = 0;
+ }
+
+void immDestroy(void)
+ {
+ immDeactivate();
+ GWN_buf_id_free(imm.vbo_id);
+ initialized = false;
+ }
+
+Gwn_VertFormat* immVertexFormat(void)
+ {
+ GWN_vertformat_clear(&imm.vertex_format);
+ return &imm.vertex_format;
+ }
+
+void immBindProgram(GLuint program, const Gwn_ShaderInterface* shaderface)
+ {
+#if TRUST_NO_ONE
+ assert(imm.bound_program == 0);
+ assert(glIsProgram(program));
+#endif
+
+ imm.bound_program = program;
+ imm.shader_interface = shaderface;
+
+ if (!imm.vertex_format.packed)
+ VertexFormat_pack(&imm.vertex_format);
+
+ glUseProgram(program);
+ get_attrib_locations(&imm.vertex_format, &imm.attrib_binding, shaderface);
+ gpuBindMatrices(shaderface);
+ }
+
+void immUnbindProgram(void)
+ {
+#if TRUST_NO_ONE
+ assert(imm.bound_program != 0);
+#endif
+
+ glUseProgram(0);
+ imm.bound_program = 0;
+ }
+
+#if TRUST_NO_ONE
+static bool vertex_count_makes_sense_for_primitive(unsigned vertex_ct, Gwn_PrimType prim_type)
+ {
+ // does vertex_ct make sense for this primitive type?
+ if (vertex_ct == 0)
+ return false;
+
+ switch (prim_type)
+ {
+ case GWN_PRIM_POINTS:
+ return true;
+ case GWN_PRIM_LINES:
+ return vertex_ct % 2 == 0;
+ case GWN_PRIM_LINE_STRIP:
+ case GWN_PRIM_LINE_LOOP:
+ return vertex_ct >= 2;
+ case GWN_PRIM_LINE_STRIP_ADJ:
+ return vertex_ct >= 4;
+ case GWN_PRIM_TRIS:
+ return vertex_ct % 3 == 0;
+ case GWN_PRIM_TRI_STRIP:
+ case GWN_PRIM_TRI_FAN:
+ return vertex_ct >= 3;
+ default:
+ return false;
+ }
+ }
+#endif
+
+void immBegin(Gwn_PrimType prim_type, unsigned vertex_ct)
+ {
+#if TRUST_NO_ONE
+ assert(initialized);
+ assert(imm.prim_type == GWN_PRIM_NONE); // make sure we haven't already begun
+ assert(vertex_count_makes_sense_for_primitive(vertex_ct, prim_type));
+#endif
+
+ imm.prim_type = prim_type;
+ imm.vertex_ct = vertex_ct;
+ imm.vertex_idx = 0;
+ imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits;
+
+ // how many bytes do we need for this draw call?
+ const unsigned bytes_needed = vertex_buffer_size(&imm.vertex_format, vertex_ct);
+
+#if TRUST_NO_ONE
+ assert(bytes_needed <= IMM_BUFFER_SIZE);
+#endif
+
+ glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id);
+
+ // does the current buffer have enough room?
+ const unsigned available_bytes = IMM_BUFFER_SIZE - imm.buffer_offset;
+ // ensure vertex data is aligned
+ const unsigned pre_padding = padding(imm.buffer_offset, imm.vertex_format.stride); // might waste a little space, but it's safe
+ if ((bytes_needed + pre_padding) <= available_bytes)
+ imm.buffer_offset += pre_padding;
+ else
+ {
+ // orphan this buffer & start with a fresh one
+#if 1
+ // this method works on all platforms, old & new
+ glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW);
+#else
+ // TODO: use other (more recent) methods after thorough testing
+ if (GLEW_VERSION_4_3 || GLEW_ARB_invalidate_subdata)
+ glInvalidateBufferData(imm.vbo_id);
+ else
+ {
+ // glitches!
+// glMapBufferRange(GL_ARRAY_BUFFER, 0, IMM_BUFFER_SIZE, GL_MAP_INVALIDATE_BUFFER_BIT);
+
+ // works
+// glMapBufferRange(GL_ARRAY_BUFFER, 0, IMM_BUFFER_SIZE,
+// GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
+// glUnmapBuffer(GL_ARRAY_BUFFER);
+
+ // also works
+ glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW);
+ }
+#endif
+
+ imm.buffer_offset = 0;
+ }
+
+// printf("mapping %u to %u\n", imm.buffer_offset, imm.buffer_offset + bytes_needed - 1);
+
+ imm.buffer_data = glMapBufferRange(GL_ARRAY_BUFFER, imm.buffer_offset, bytes_needed,
+ GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | (imm.strict_vertex_ct ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT));
+
+#if TRUST_NO_ONE
+ assert(imm.buffer_data != NULL);
+#endif
+
+ imm.buffer_bytes_mapped = bytes_needed;
+ imm.vertex_data = imm.buffer_data;
+ }
+
+void immBeginAtMost(Gwn_PrimType prim_type, unsigned vertex_ct)
+ {
+#if TRUST_NO_ONE
+ assert(vertex_ct > 0);
+#endif
+
+ imm.strict_vertex_ct = false;
+ immBegin(prim_type, vertex_ct);
+ }
+
+#if IMM_BATCH_COMBO
+
+Gwn_Batch* immBeginBatch(Gwn_PrimType prim_type, unsigned vertex_ct)
+ {
+#if TRUST_NO_ONE
+ assert(initialized);
+ assert(imm.prim_type == GWN_PRIM_NONE); // make sure we haven't already begun
+ assert(vertex_count_makes_sense_for_primitive(vertex_ct, prim_type));
+#endif
+
+ imm.prim_type = prim_type;
+ imm.vertex_ct = vertex_ct;
+ imm.vertex_idx = 0;
+ imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits;
+
+ Gwn_VertBuf* verts = GWN_vertbuf_create_with_format(&imm.vertex_format);
+ GWN_vertbuf_data_alloc(verts, vertex_ct);
+
+ imm.buffer_bytes_mapped = GWN_vertbuf_size_get(verts);
+ imm.vertex_data = verts->data;
+
+ imm.batch = GWN_batch_create(prim_type, verts, NULL);
+ imm.batch->phase = GWN_BATCH_BUILDING;
+
+ GWN_batch_program_set(imm.batch, imm.bound_program, imm.shader_interface);
+
+ return imm.batch;
+ }
+
+Gwn_Batch* immBeginBatchAtMost(Gwn_PrimType prim_type, unsigned vertex_ct)
+ {
+ imm.strict_vertex_ct = false;
+ return immBeginBatch(prim_type, vertex_ct);
+ }
+
+#endif // IMM_BATCH_COMBO
+
+static void immDrawSetup(void)
+ {
+ // set up VAO -- can be done during Begin or End really
+ glBindVertexArray(imm.vao_id);
+
+ // enable/disable vertex attribs as needed
+ if (imm.attrib_binding.enabled_bits != imm.prev_enabled_attrib_bits)
+ {
+ for (unsigned loc = 0; loc < GWN_VERT_ATTR_MAX_LEN; ++loc)
+ {
+ bool is_enabled = imm.attrib_binding.enabled_bits & (1 << loc);
+ bool was_enabled = imm.prev_enabled_attrib_bits & (1 << loc);
+
+ if (is_enabled && !was_enabled)
+ {
+// printf("enabling attrib %u\n", loc);
+ glEnableVertexAttribArray(loc);
+ }
+ else if (was_enabled && !is_enabled)
+ {
+// printf("disabling attrib %u\n", loc);
+ glDisableVertexAttribArray(loc);
+ }
+ }
+
+ imm.prev_enabled_attrib_bits = imm.attrib_binding.enabled_bits;
+ }
+
+ const unsigned stride = imm.vertex_format.stride;
+
+ for (unsigned a_idx = 0; a_idx < imm.vertex_format.attrib_ct; ++a_idx)
+ {
+ const Gwn_VertAttr* a = imm.vertex_format.attribs + a_idx;
+
+ const unsigned offset = imm.buffer_offset + a->offset;
+ const GLvoid* pointer = (const GLubyte*)0 + offset;
+
+ const unsigned loc = read_attrib_location(&imm.attrib_binding, a_idx);
+
+// printf("specifying attrib %u '%s' with offset %u, stride %u\n", loc, a->name, offset, stride);
+
+ switch (a->fetch_mode)
+ {
+ case GWN_FETCH_FLOAT:
+ case GWN_FETCH_INT_TO_FLOAT:
+ glVertexAttribPointer(loc, a->comp_ct, a->gl_comp_type, GL_FALSE, stride, pointer);
+ break;
+ case GWN_FETCH_INT_TO_FLOAT_UNIT:
+ glVertexAttribPointer(loc, a->comp_ct, a->gl_comp_type, GL_TRUE, stride, pointer);
+ break;
+ case GWN_FETCH_INT:
+ glVertexAttribIPointer(loc, a->comp_ct, a->gl_comp_type, stride, pointer);
+ }
+ }
+
+ if (gpuMatricesDirty())
+ gpuBindMatrices(imm.shader_interface);
+ }
+
+void immEnd(void)
+ {
+#if TRUST_NO_ONE
+ assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair
+#endif
+
+ unsigned buffer_bytes_used;
+ if (imm.strict_vertex_ct)
+ {
+#if TRUST_NO_ONE
+ assert(imm.vertex_idx == imm.vertex_ct); // with all vertices defined
+#endif
+ buffer_bytes_used = imm.buffer_bytes_mapped;
+ }
+ else
+ {
+#if TRUST_NO_ONE
+ assert(imm.vertex_idx <= imm.vertex_ct);
+#endif
+ // printf("used %u of %u verts,", imm.vertex_idx, imm.vertex_ct);
+ if (imm.vertex_idx == imm.vertex_ct)
+ {
+ buffer_bytes_used = imm.buffer_bytes_mapped;
+ }
+ else
+ {
+#if TRUST_NO_ONE
+ assert(imm.vertex_idx == 0 || vertex_count_makes_sense_for_primitive(imm.vertex_idx, imm.prim_type));
+#endif
+ imm.vertex_ct = imm.vertex_idx;
+ buffer_bytes_used = vertex_buffer_size(&imm.vertex_format, imm.vertex_ct);
+ // unused buffer bytes are available to the next immBegin
+ // printf(" %u of %u bytes\n", buffer_bytes_used, imm.buffer_bytes_mapped);
+ }
+
+ // tell OpenGL what range was modified so it doesn't copy the whole mapped range
+ // printf("flushing %u to %u\n", imm.buffer_offset, imm.buffer_offset + buffer_bytes_used - 1);
+ glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, buffer_bytes_used);
+ }
+
+#if IMM_BATCH_COMBO
+ if (imm.batch)
+ {
+ if (buffer_bytes_used != imm.buffer_bytes_mapped)
+ {
+ GWN_vertbuf_data_resize(imm.batch->verts[0], imm.vertex_ct);
+ // TODO: resize only if vertex count is much smaller
+ }
+
+ imm.batch->phase = GWN_BATCH_READY_TO_DRAW;
+ imm.batch = NULL; // don't free, batch belongs to caller
+ }
+ else
+#endif
+ {
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+
+ if (imm.vertex_ct > 0)
+ {
+ immDrawSetup();
+ glDrawArrays(convert_prim_type_to_gl(imm.prim_type), 0, imm.vertex_ct);
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+
+ // prep for next immBegin
+ imm.buffer_offset += buffer_bytes_used;
+ }
+
+ // prep for next immBegin
+ imm.prim_type = GWN_PRIM_NONE;
+ imm.strict_vertex_ct = true;
+ }
+
+static void setAttribValueBit(unsigned attrib_id)
+ {
+ uint16_t mask = 1 << attrib_id;
+
+#if TRUST_NO_ONE
+ assert(imm.unassigned_attrib_bits & mask); // not already set
+#endif
+
+ imm.unassigned_attrib_bits &= ~mask;
+ }
+
+
+// --- generic attribute functions ---
+
+void immAttrib1f(unsigned attrib_id, float x)
+ {
+ Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id;
+
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attrib_ct);
+ assert(attrib->comp_type == GWN_COMP_F32);
+ assert(attrib->comp_ct == 1);
+ assert(imm.vertex_idx < imm.vertex_ct);
+ assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair
+#endif
+
+ setAttribValueBit(attrib_id);
+
+ float* data = (float*)(imm.vertex_data + attrib->offset);
+// printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data);
+
+ data[0] = x;
+ }
+
+void immAttrib2f(unsigned attrib_id, float x, float y)
+ {
+ Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id;
+
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attrib_ct);
+ assert(attrib->comp_type == GWN_COMP_F32);
+ assert(attrib->comp_ct == 2);
+ assert(imm.vertex_idx < imm.vertex_ct);
+ assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair
+#endif
+
+ setAttribValueBit(attrib_id);
+
+ float* data = (float*)(imm.vertex_data + attrib->offset);
+// printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data);
+
+ data[0] = x;
+ data[1] = y;
+ }
+
+void immAttrib3f(unsigned attrib_id, float x, float y, float z)
+ {
+ Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id;
+
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attrib_ct);
+ assert(attrib->comp_type == GWN_COMP_F32);
+ assert(attrib->comp_ct == 3);
+ assert(imm.vertex_idx < imm.vertex_ct);
+ assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair
+#endif
+
+ setAttribValueBit(attrib_id);
+
+ float* data = (float*)(imm.vertex_data + attrib->offset);
+// printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data);
+
+ data[0] = x;
+ data[1] = y;
+ data[2] = z;
+ }
+
+void immAttrib4f(unsigned attrib_id, float x, float y, float z, float w)
+ {
+ Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id;
+
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attrib_ct);
+ assert(attrib->comp_type == GWN_COMP_F32);
+ assert(attrib->comp_ct == 4);
+ assert(imm.vertex_idx < imm.vertex_ct);
+ assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair
+#endif
+
+ setAttribValueBit(attrib_id);
+
+ float* data = (float*)(imm.vertex_data + attrib->offset);
+// printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data);
+
+ data[0] = x;
+ data[1] = y;
+ data[2] = z;
+ data[3] = w;
+ }
+
+void immAttrib1u(unsigned attrib_id, unsigned x)
+ {
+ Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id;
+
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attrib_ct);
+ assert(attrib->comp_type == GWN_COMP_U32);
+ assert(attrib->comp_ct == 1);
+ assert(imm.vertex_idx < imm.vertex_ct);
+ assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair
+#endif
+
+ setAttribValueBit(attrib_id);
+
+ unsigned* data = (unsigned*)(imm.vertex_data + attrib->offset);
+
+ data[0] = x;
+ }
+
+void immAttrib2i(unsigned attrib_id, int x, int y)
+ {
+ Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id;
+
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attrib_ct);
+ assert(attrib->comp_type == GWN_COMP_I32);
+ assert(attrib->comp_ct == 2);
+ assert(imm.vertex_idx < imm.vertex_ct);
+ assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair
+#endif
+
+ setAttribValueBit(attrib_id);
+
+ int* data = (int*)(imm.vertex_data + attrib->offset);
+
+ data[0] = x;
+ data[1] = y;
+ }
+
+void immAttrib2s(unsigned attrib_id, short x, short y)
+ {
+ Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id;
+
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attrib_ct);
+ assert(attrib->comp_type == GWN_COMP_I16);
+ assert(attrib->comp_ct == 2);
+ assert(imm.vertex_idx < imm.vertex_ct);
+ assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair
+#endif
+
+ setAttribValueBit(attrib_id);
+
+ short* data = (short*)(imm.vertex_data + attrib->offset);
+
+ data[0] = x;
+ data[1] = y;
+ }
+
+void immAttrib2fv(unsigned attrib_id, const float data[2])
+ {
+ immAttrib2f(attrib_id, data[0], data[1]);
+ }
+
+void immAttrib3fv(unsigned attrib_id, const float data[3])
+ {
+ immAttrib3f(attrib_id, data[0], data[1], data[2]);
+ }
+
+void immAttrib4fv(unsigned attrib_id, const float data[4])
+ {
+ immAttrib4f(attrib_id, data[0], data[1], data[2], data[3]);
+ }
+
+void immAttrib3ub(unsigned attrib_id, unsigned char r, unsigned char g, unsigned char b)
+ {
+ Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id;
+
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attrib_ct);
+ assert(attrib->comp_type == GWN_COMP_U8);
+ assert(attrib->comp_ct == 3);
+ assert(imm.vertex_idx < imm.vertex_ct);
+ assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair
+#endif
+
+ setAttribValueBit(attrib_id);
+
+ GLubyte* data = imm.vertex_data + attrib->offset;
+// printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data);
+
+ data[0] = r;
+ data[1] = g;
+ data[2] = b;
+ }
+
+void immAttrib4ub(unsigned attrib_id, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+ {
+ Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id;
+
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attrib_ct);
+ assert(attrib->comp_type == GWN_COMP_U8);
+ assert(attrib->comp_ct == 4);
+ assert(imm.vertex_idx < imm.vertex_ct);
+ assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair
+#endif
+
+ setAttribValueBit(attrib_id);
+
+ GLubyte* data = imm.vertex_data + attrib->offset;
+// printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data);
+
+ data[0] = r;
+ data[1] = g;
+ data[2] = b;
+ data[3] = a;
+ }
+
+void immAttrib3ubv(unsigned attrib_id, const unsigned char data[3])
+ {
+ immAttrib3ub(attrib_id, data[0], data[1], data[2]);
+ }
+
+void immAttrib4ubv(unsigned attrib_id, const unsigned char data[4])
+ {
+ immAttrib4ub(attrib_id, data[0], data[1], data[2], data[3]);
+ }
+
+void immSkipAttrib(unsigned attrib_id)
+ {
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attrib_ct);
+ assert(imm.vertex_idx < imm.vertex_ct);
+ assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair
+#endif
+
+ setAttribValueBit(attrib_id);
+ }
+
+static void immEndVertex(void) // and move on to the next vertex
+ {
+#if TRUST_NO_ONE
+ assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair
+ assert(imm.vertex_idx < imm.vertex_ct);
+#endif
+
+ // have all attribs been assigned values?
+ // if not, copy value from previous vertex
+ if (imm.unassigned_attrib_bits)
+ {
+#if TRUST_NO_ONE
+ assert(imm.vertex_idx > 0); // first vertex must have all attribs specified
+#endif
+
+ for (unsigned a_idx = 0; a_idx < imm.vertex_format.attrib_ct; ++a_idx)
+ {
+ if ((imm.unassigned_attrib_bits >> a_idx) & 1)
+ {
+ const Gwn_VertAttr* a = imm.vertex_format.attribs + a_idx;
+
+// printf("copying %s from vertex %u to %u\n", a->name, imm.vertex_idx - 1, imm.vertex_idx);
+
+ GLubyte* data = imm.vertex_data + a->offset;
+ memcpy(data, data - imm.vertex_format.stride, a->sz);
+ // TODO: consolidate copy of adjacent attributes
+ }
+ }
+ }
+
+ imm.vertex_idx++;
+ imm.vertex_data += imm.vertex_format.stride;
+ imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits;
+ }
+
+void immVertex2f(unsigned attrib_id, float x, float y)
+ {
+ immAttrib2f(attrib_id, x, y);
+ immEndVertex();
+ }
+
+void immVertex3f(unsigned attrib_id, float x, float y, float z)
+ {
+ immAttrib3f(attrib_id, x, y, z);
+ immEndVertex();
+ }
+
+void immVertex2i(unsigned attrib_id, int x, int y)
+ {
+ immAttrib2i(attrib_id, x, y);
+ immEndVertex();
+ }
+
+void immVertex2s(unsigned attrib_id, short x, short y)
+ {
+ immAttrib2s(attrib_id, x, y);
+ immEndVertex();
+ }
+
+void immVertex2fv(unsigned attrib_id, const float data[2])
+ {
+ immAttrib2f(attrib_id, data[0], data[1]);
+ immEndVertex();
+ }
+
+void immVertex3fv(unsigned attrib_id, const float data[3])
+ {
+ immAttrib3f(attrib_id, data[0], data[1], data[2]);
+ immEndVertex();
+ }
+
+void immVertex2iv(unsigned attrib_id, const int data[2])
+ {
+ immAttrib2i(attrib_id, data[0], data[1]);
+ immEndVertex();
+ }
+
+
+// --- generic uniform functions ---
+
+#if 0
+ #if TRUST_NO_ONE
+ #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(imm.shader_interface, name); assert(uniform);
+ #else
+ #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(imm.shader_interface, name);
+ #endif
+#else
+ // NOTE: It is possible to have uniform fully optimized out from the shader.
+ // In this case we can't assert failure or allow NULL-pointer dereference.
+ // TODO(sergey): How can we detect existing-but-optimized-out uniform but still
+ // catch typos in uniform names passed to immUniform*() functions?
+ #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(imm.shader_interface, name); if (uniform == NULL) return;
+#endif
+
+void immUniform1f(const char* name, float x)
+ {
+ GET_UNIFORM
+ glUniform1f(uniform->location, x);
+ }
+
+void immUniform2f(const char* name, float x, float y)
+ {
+ GET_UNIFORM
+ glUniform2f(uniform->location, x, y);
+ }
+
+void immUniform2fv(const char* name, const float data[2])
+ {
+ GET_UNIFORM
+ glUniform2fv(uniform->location, 1, data);
+ }
+
+void immUniform3f(const char* name, float x, float y, float z)
+ {
+ GET_UNIFORM
+ glUniform3f(uniform->location, x, y, z);
+ }
+
+void immUniform3fv(const char* name, const float data[3])
+ {
+ GET_UNIFORM
+ glUniform3fv(uniform->location, 1, data);
+ }
+
+// can increase this limit or move to another file
+#define MAX_UNIFORM_NAME_LEN 60
+
+void immUniformArray3fv(const char* bare_name, const float *data, int count)
+ {
+ // look up "name[0]" when given "name"
+ const size_t len = strlen(bare_name);
+#if TRUST_NO_ONE
+ assert(len <= MAX_UNIFORM_NAME_LEN);
+#endif
+ char name[MAX_UNIFORM_NAME_LEN];
+ strcpy(name, bare_name);
+ name[len + 0] = '[';
+ name[len + 1] = '0';
+ name[len + 2] = ']';
+ name[len + 3] = '\0';
+
+ GET_UNIFORM
+ glUniform3fv(uniform->location, count, data);
+ }
+
+void immUniform4f(const char* name, float x, float y, float z, float w)
+ {
+ GET_UNIFORM
+ glUniform4f(uniform->location, x, y, z, w);
+ }
+
+void immUniform4fv(const char* name, const float data[4])
+ {
+ GET_UNIFORM
+ glUniform4fv(uniform->location, 1, data);
+ }
+
+void immUniformArray4fv(const char* bare_name, const float *data, int count)
+ {
+ // look up "name[0]" when given "name"
+ const size_t len = strlen(bare_name);
+#if TRUST_NO_ONE
+ assert(len <= MAX_UNIFORM_NAME_LEN);
+#endif
+ char name[MAX_UNIFORM_NAME_LEN];
+ strcpy(name, bare_name);
+ name[len + 0] = '[';
+ name[len + 1] = '0';
+ name[len + 2] = ']';
+ name[len + 3] = '\0';
+
+ GET_UNIFORM
+ glUniform4fv(uniform->location, count, data);
+ }
+
+void immUniformMatrix4fv(const char* name, const float data[4][4])
+ {
+ GET_UNIFORM
+ glUniformMatrix4fv(uniform->location, 1, GL_FALSE, (float *)data);
+ }
+
+void immUniform1i(const char* name, int x)
+ {
+ GET_UNIFORM
+ glUniform1i(uniform->location, x);
+ }
+
+void immUniform4iv(const char* name, const int data[4])
+ {
+ GET_UNIFORM
+ glUniform4iv(uniform->location, 1, data);
+ }
+
+// --- convenience functions for setting "uniform vec4 color" ---
+
+void immUniformColor4f(float r, float g, float b, float a)
+ {
+ const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform_builtin(imm.shader_interface, GWN_UNIFORM_COLOR);
+
+#if TRUST_NO_ONE
+ assert(uniform != NULL);
+#endif
+
+ glUniform4f(uniform->location, r, g, b, a);
+ }
+
+void immUniformColor4fv(const float rgba[4])
+ {
+ immUniformColor4f(rgba[0], rgba[1], rgba[2], rgba[3]);
+ }
+
+void immUniformColor3f(float r, float g, float b)
+ {
+ immUniformColor4f(r, g, b, 1.0f);
+ }
+
+void immUniformColor3fv(const float rgb[3])
+ {
+ immUniformColor4f(rgb[0], rgb[1], rgb[2], 1.0f);
+ }
+
+void immUniformColor3fvAlpha(const float rgb[3], float a)
+ {
+ immUniformColor4f(rgb[0], rgb[1], rgb[2], a);
+ }
+
+// TODO: v-- treat as sRGB? --v
+
+void immUniformColor3ub(unsigned char r, unsigned char g, unsigned char b)
+ {
+ const float scale = 1.0f / 255.0f;
+ immUniformColor4f(scale * r, scale * g, scale * b, 1.0f);
+ }
+
+void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+ {
+ const float scale = 1.0f / 255.0f;
+ immUniformColor4f(scale * r, scale * g, scale * b, scale * a);
+ }
+
+void immUniformColor3ubv(const unsigned char rgb[3])
+ {
+ immUniformColor3ub(rgb[0], rgb[1], rgb[2]);
+ }
+
+void immUniformColor3ubvAlpha(const unsigned char rgb[3], unsigned char alpha)
+ {
+ immUniformColor4ub(rgb[0], rgb[1], rgb[2], alpha);
+ }
+
+void immUniformColor4ubv(const unsigned char rgba[4])
+ {
+ immUniformColor4ub(rgba[0], rgba[1], rgba[2], rgba[3]);
+ }
diff --git a/intern/gawain/src/primitive.c b/intern/gawain/src/primitive.c
new file mode 100644
index 00000000000..b9d92a6bdf8
--- /dev/null
+++ b/intern/gawain/src/primitive.c
@@ -0,0 +1,63 @@
+
+// Gawain geometric primitives
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2017 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#include "primitive.h"
+#include "primitive_private.h"
+
+Gwn_PrimClass GWN_primtype_class(Gwn_PrimType prim_type)
+ {
+ static const Gwn_PrimClass classes[] =
+ {
+ [GWN_PRIM_POINTS] = GWN_PRIM_CLASS_POINT,
+ [GWN_PRIM_LINES] = GWN_PRIM_CLASS_LINE,
+ [GWN_PRIM_LINE_STRIP] = GWN_PRIM_CLASS_LINE,
+ [GWN_PRIM_LINE_LOOP] = GWN_PRIM_CLASS_LINE,
+ [GWN_PRIM_TRIS] = GWN_PRIM_CLASS_SURFACE,
+ [GWN_PRIM_TRI_STRIP] = GWN_PRIM_CLASS_SURFACE,
+ [GWN_PRIM_TRI_FAN] = GWN_PRIM_CLASS_SURFACE,
+
+ [GWN_PRIM_LINE_STRIP_ADJ] = GWN_PRIM_CLASS_LINE,
+
+ [GWN_PRIM_NONE] = GWN_PRIM_CLASS_NONE
+ };
+
+ return classes[prim_type];
+ }
+
+bool GWN_primtype_belongs_to_class(Gwn_PrimType prim_type, Gwn_PrimClass prim_class)
+ {
+ if (prim_class == GWN_PRIM_CLASS_NONE && prim_type == GWN_PRIM_NONE)
+ return true;
+
+ return prim_class & GWN_primtype_class(prim_type);
+ }
+
+GLenum convert_prim_type_to_gl(Gwn_PrimType prim_type)
+ {
+#if TRUST_NO_ONE
+ assert(prim_type != GWN_PRIM_NONE);
+#endif
+
+ static const GLenum table[] =
+ {
+ [GWN_PRIM_POINTS] = GL_POINTS,
+ [GWN_PRIM_LINES] = GL_LINES,
+ [GWN_PRIM_LINE_STRIP] = GL_LINE_STRIP,
+ [GWN_PRIM_LINE_LOOP] = GL_LINE_LOOP,
+ [GWN_PRIM_TRIS] = GWN_PRIM_CLASS_SURFACE,
+ [GWN_PRIM_TRI_STRIP] = GL_TRIANGLE_STRIP,
+ [GWN_PRIM_TRI_FAN] = GL_TRIANGLE_FAN,
+
+ [GWN_PRIM_LINE_STRIP_ADJ] = GL_LINE_STRIP_ADJACENCY,
+ };
+
+ return table[prim_type];
+ }
diff --git a/intern/gawain/src/shader_interface.c b/intern/gawain/src/shader_interface.c
new file mode 100644
index 00000000000..dff2c06f531
--- /dev/null
+++ b/intern/gawain/src/shader_interface.c
@@ -0,0 +1,311 @@
+
+// Gawain shader interface (C --> GLSL)
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2017 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#include "shader_interface.h"
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#define SUPPORT_LEGACY_GLSL 1
+#define DEBUG_SHADER_INTERFACE 0
+
+#if DEBUG_SHADER_INTERFACE
+ #include <stdio.h>
+#endif
+
+static const char* BuiltinUniform_name(Gwn_UniformBuiltin u)
+ {
+ static const char* names[] =
+ {
+ [GWN_UNIFORM_NONE] = NULL,
+
+ [GWN_UNIFORM_MODELVIEW] = "ModelViewMatrix",
+ [GWN_UNIFORM_PROJECTION] = "ProjectionMatrix",
+ [GWN_UNIFORM_MVP] = "ModelViewProjectionMatrix",
+
+ [GWN_UNIFORM_MODELVIEW_INV] = "ModelViewInverseMatrix",
+ [GWN_UNIFORM_PROJECTION_INV] = "ProjectionInverseMatrix",
+
+ [GWN_UNIFORM_NORMAL] = "NormalMatrix",
+
+ [GWN_UNIFORM_COLOR] = "color",
+
+ [GWN_UNIFORM_CUSTOM] = NULL
+ };
+
+ return names[u];
+ }
+
+static bool match(const char* a, const char* b)
+ {
+ return strcmp(a, b) == 0;
+ }
+
+static unsigned hash_string(const char *str)
+ {
+ unsigned i = 0, c;
+
+ while ((c = *str++))
+ {
+ i = i * 37 + c;
+ }
+
+ return i;
+ }
+
+static void set_input_name(Gwn_ShaderInput* input, const char* name)
+ {
+ input->name = name;
+ input->name_hash = hash_string(name);
+ }
+
+// keep these in sync with Gwn_UniformBuiltin order
+#define FIRST_MAT4_UNIFORM GWN_UNIFORM_MODELVIEW
+#define LAST_MAT4_UNIFORM GWN_UNIFORM_PROJECTION_INV
+
+static bool setup_builtin_uniform(Gwn_ShaderInput* input, const char* name)
+ {
+ // TODO: reject DOUBLE, IMAGE, ATOMIC_COUNTER gl_types
+
+ // detect built-in uniforms (gl_type and name must match)
+ // if a match is found, use BuiltinUniform_name so name buffer space can be reclaimed
+ switch (input->gl_type)
+ {
+ case GL_FLOAT_MAT4:
+ for (Gwn_UniformBuiltin u = FIRST_MAT4_UNIFORM; u <= LAST_MAT4_UNIFORM; ++u)
+ {
+ const char* builtin_name = BuiltinUniform_name(u);
+ if (match(name, builtin_name))
+ {
+ set_input_name(input, builtin_name);
+ input->builtin_type = u;
+ return true;
+ }
+ }
+ break;
+ case GL_FLOAT_MAT3:
+ {
+ const char* builtin_name = BuiltinUniform_name(GWN_UNIFORM_NORMAL);
+ if (match(name, builtin_name))
+ {
+ set_input_name(input, builtin_name);
+ input->builtin_type = GWN_UNIFORM_NORMAL;
+ return true;
+ }
+ }
+ break;
+ case GL_FLOAT_VEC4:
+ {
+ const char* builtin_name = BuiltinUniform_name(GWN_UNIFORM_COLOR);
+ if (match(name, builtin_name))
+ {
+ set_input_name(input, builtin_name);
+ input->builtin_type = GWN_UNIFORM_COLOR;
+ return true;
+ }
+ }
+ break;
+ default:
+ ;
+ }
+
+ input->builtin_type = GWN_UNIFORM_CUSTOM;
+ return false;
+ }
+
+Gwn_ShaderInterface* GWN_shaderinterface_create(GLint program)
+ {
+#if DEBUG_SHADER_INTERFACE
+ printf("%s {\n", __func__); // enter function
+#endif
+
+ GLint uniform_ct, attrib_ct;
+ glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniform_ct);
+ glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attrib_ct);
+ const GLint input_ct = uniform_ct + attrib_ct;
+
+ GLint max_uniform_name_len, max_attrib_name_len;
+ glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_len);
+ glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attrib_name_len);
+ const uint32_t name_buffer_len = uniform_ct * max_uniform_name_len + attrib_ct * max_attrib_name_len;
+
+ // allocate enough space for input counts, details for each input, and a buffer for name strings
+ Gwn_ShaderInterface* shaderface = calloc(1, offsetof(Gwn_ShaderInterface, inputs) + input_ct * sizeof(Gwn_ShaderInput) + name_buffer_len);
+ shaderface->uniform_ct = uniform_ct;
+ shaderface->attrib_ct = attrib_ct;
+
+ char* name_buffer = (char*)shaderface + offsetof(Gwn_ShaderInterface, inputs) + input_ct * sizeof(Gwn_ShaderInput);
+ uint32_t name_buffer_offset = 0;
+
+ for (uint32_t i = 0; i < uniform_ct; ++i)
+ {
+ Gwn_ShaderInput* input = shaderface->inputs + i;
+ GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
+ char* name = name_buffer + name_buffer_offset;
+ GLsizei name_len = 0;
+
+ glGetActiveUniform(program, i, remaining_buffer, &name_len, &input->size, &input->gl_type, name);
+
+ input->location = glGetUniformLocation(program, name);
+
+#if SUPPORT_LEGACY_GLSL
+ if (input->location != -1)
+ {
+#elif TRUST_NO_ONE
+ assert(input->location != -1);
+#endif
+
+ if (setup_builtin_uniform(input, name))
+ ; // reclaim space from name buffer (don't advance offset)
+ else
+ {
+ set_input_name(input, name);
+ name_buffer_offset += name_len + 1; // include NULL terminator
+ }
+#if SUPPORT_LEGACY_GLSL
+ }
+#endif
+
+#if DEBUG_SHADER_INTERFACE
+ printf("uniform[%u] '%s' at location %d\n", i, name, input->location);
+#endif
+ }
+
+ for (uint32_t i = 0; i < attrib_ct; ++i)
+ {
+ Gwn_ShaderInput* input = shaderface->inputs + uniform_ct + i;
+ GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
+ char* name = name_buffer + name_buffer_offset;
+ GLsizei name_len = 0;
+
+ glGetActiveAttrib(program, i, remaining_buffer, &name_len, &input->size, &input->gl_type, name);
+
+ // TODO: reject DOUBLE gl_types
+
+ input->location = glGetAttribLocation(program, name);
+
+#if SUPPORT_LEGACY_GLSL
+ if (input->location != -1)
+ {
+#elif TRUST_NO_ONE
+ assert(input->location != -1);
+#endif
+
+ set_input_name(input, name);
+ name_buffer_offset += name_len + 1; // include NULL terminator
+#if SUPPORT_LEGACY_GLSL
+ }
+#endif
+
+#if DEBUG_SHADER_INTERFACE
+ printf("attrib[%u] '%s' at location %d\n", i, name, input->location);
+#endif
+ }
+
+ const uint32_t name_buffer_used = name_buffer_offset;
+
+#if DEBUG_SHADER_INTERFACE
+ printf("using %u of %u bytes from name buffer\n", name_buffer_used, name_buffer_len);
+ printf("}\n"); // exit function
+#endif
+
+ if (name_buffer_used < name_buffer_len)
+ {
+ // realloc shaderface to shrink name buffer
+ const size_t shaderface_alloc =
+ offsetof(Gwn_ShaderInterface, inputs) + (input_ct * sizeof(Gwn_ShaderInput)) + name_buffer_used;
+ const char* shaderface_orig_start = (const char*)shaderface;
+ const char* shaderface_orig_end = &shaderface_orig_start[shaderface_alloc];
+ shaderface = realloc(shaderface, shaderface_alloc);
+ const ptrdiff_t delta = (char*)shaderface - shaderface_orig_start;
+
+ if (delta)
+ {
+ // each input->name will need adjustment (except static built-in names)
+ for (uint32_t i = 0; i < input_ct; ++i)
+ {
+ Gwn_ShaderInput* input = shaderface->inputs + i;
+
+ if (input->name >= shaderface_orig_start && input->name < shaderface_orig_end)
+ input->name += delta;
+ }
+ }
+ }
+
+ return shaderface;
+ }
+
+void GWN_shaderinterface_discard(Gwn_ShaderInterface* shaderface)
+ {
+ // allocated as one chunk, so discard is simple
+ free(shaderface);
+ }
+
+const Gwn_ShaderInput* GWN_shaderinterface_uniform(const Gwn_ShaderInterface* shaderface, const char* name)
+ {
+ const unsigned name_hash = hash_string(name);
+ for (uint32_t i = 0; i < shaderface->uniform_ct; ++i)
+ {
+ const Gwn_ShaderInput* uniform = shaderface->inputs + i;
+
+#if SUPPORT_LEGACY_GLSL
+ if (uniform->name == NULL) continue;
+#endif
+
+ if (uniform->name_hash != name_hash) continue;
+
+ if (match(uniform->name, name))
+ return uniform;
+
+ // TODO: warn if we find a matching builtin, since these can be looked up much quicker --v
+ }
+
+ return NULL; // not found
+ }
+
+const Gwn_ShaderInput* GWN_shaderinterface_uniform_builtin(const Gwn_ShaderInterface* shaderface, Gwn_UniformBuiltin builtin)
+ {
+#if TRUST_NO_ONE
+ assert(builtin != GWN_UNIFORM_NONE);
+ assert(builtin != GWN_UNIFORM_CUSTOM);
+#endif
+
+ // look up by enum, not name
+ for (uint32_t i = 0; i < shaderface->uniform_ct; ++i)
+ {
+ const Gwn_ShaderInput* uniform = shaderface->inputs + i;
+
+ if (uniform->builtin_type == builtin)
+ return uniform;
+ }
+ return NULL; // not found
+ }
+
+const Gwn_ShaderInput* GWN_shaderinterface_attr(const Gwn_ShaderInterface* shaderface, const char* name)
+ {
+ // attribs are stored after uniforms
+ const uint32_t input_ct = shaderface->uniform_ct + shaderface->attrib_ct;
+ const unsigned name_hash = hash_string(name);
+ for (uint32_t i = shaderface->uniform_ct; i < input_ct; ++i)
+ {
+ const Gwn_ShaderInput* attrib = shaderface->inputs + i;
+
+#if SUPPORT_LEGACY_GLSL
+ if (attrib->name == NULL) continue;
+#endif
+
+ if (attrib->name_hash != name_hash) continue;
+
+ if (match(attrib->name, name))
+ return attrib;
+ }
+ return NULL; // not found
+ }
diff --git a/intern/gawain/src/vertex_buffer.c b/intern/gawain/src/vertex_buffer.c
new file mode 100644
index 00000000000..364e16a1a68
--- /dev/null
+++ b/intern/gawain/src/vertex_buffer.c
@@ -0,0 +1,222 @@
+
+// Gawain vertex buffer
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#include "vertex_buffer.h"
+#include "buffer_id.h"
+#include "vertex_format_private.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define KEEP_SINGLE_COPY 1
+
+static unsigned vbo_memory_usage;
+
+Gwn_VertBuf* GWN_vertbuf_create(void)
+ {
+ Gwn_VertBuf* verts = malloc(sizeof(Gwn_VertBuf));
+ GWN_vertbuf_init(verts);
+ return verts;
+ }
+
+Gwn_VertBuf* GWN_vertbuf_create_with_format(const Gwn_VertFormat* format)
+ {
+ Gwn_VertBuf* verts = GWN_vertbuf_create();
+ GWN_vertformat_copy(&verts->format, format);
+ if (!format->packed)
+ VertexFormat_pack(&verts->format);
+ return verts;
+
+ // this function might seem redundant, but there is potential for memory savings here...
+ // TODO: implement those memory savings
+ }
+
+void GWN_vertbuf_init(Gwn_VertBuf* verts)
+ {
+ memset(verts, 0, sizeof(Gwn_VertBuf));
+ }
+
+void GWN_vertbuf_init_with_format(Gwn_VertBuf* verts, const Gwn_VertFormat* format)
+ {
+ GWN_vertbuf_init(verts);
+ GWN_vertformat_copy(&verts->format, format);
+ if (!format->packed)
+ VertexFormat_pack(&verts->format);
+ }
+
+/**
+ * Like #GWN_vertbuf_discard but doesn't free.
+ */
+void GWN_vertbuf_clear(Gwn_VertBuf* verts)
+ {
+ if (verts->vbo_id) {
+ GWN_buf_id_free(verts->vbo_id);
+ vbo_memory_usage -= GWN_vertbuf_size_get(verts);
+ }
+#if KEEP_SINGLE_COPY
+ else
+#endif
+ if (verts->data)
+ {
+ free(verts->data);
+ verts->data = NULL;
+ }
+ }
+
+void GWN_vertbuf_discard(Gwn_VertBuf* verts)
+ {
+ if (verts->vbo_id) {
+ GWN_buf_id_free(verts->vbo_id);
+ vbo_memory_usage -= GWN_vertbuf_size_get(verts);
+ }
+#if KEEP_SINGLE_COPY
+ else
+#endif
+ if (verts->data)
+ free(verts->data);
+
+
+ free(verts);
+ }
+
+unsigned GWN_vertbuf_size_get(const Gwn_VertBuf* verts)
+ {
+ return vertex_buffer_size(&verts->format, verts->vertex_ct);
+ }
+
+void GWN_vertbuf_data_alloc(Gwn_VertBuf* verts, unsigned v_ct)
+ {
+ Gwn_VertFormat* format = &verts->format;
+ if (!format->packed)
+ VertexFormat_pack(format);
+
+ verts->vertex_ct = v_ct;
+
+ // Data initially lives in main memory. Will be transferred to VRAM when we "prime" it.
+ verts->data = malloc(GWN_vertbuf_size_get(verts));
+ }
+
+void GWN_vertbuf_data_resize(Gwn_VertBuf* verts, unsigned v_ct)
+ {
+#if TRUST_NO_ONE
+ assert(verts->vertex_ct != v_ct); // allow this?
+ assert(verts->data != NULL); // has already been allocated
+ assert(verts->vbo_id == 0); // has not been sent to VRAM
+#endif
+
+ verts->vertex_ct = v_ct;
+ verts->data = realloc(verts->data, GWN_vertbuf_size_get(verts));
+ // TODO: skip realloc if v_ct < existing vertex count
+ // extra space will be reclaimed, and never sent to VRAM (see VertexBuffer_prime)
+ }
+
+void GWN_vertbuf_attr_set(Gwn_VertBuf* verts, unsigned a_idx, unsigned v_idx, const void* data)
+ {
+ const Gwn_VertFormat* format = &verts->format;
+ const Gwn_VertAttr* a = format->attribs + a_idx;
+
+#if TRUST_NO_ONE
+ assert(a_idx < format->attrib_ct);
+ assert(v_idx < verts->vertex_ct);
+ assert(verts->data != NULL); // data must be in main mem
+#endif
+
+ memcpy((GLubyte*)verts->data + a->offset + v_idx * format->stride, data, a->sz);
+ }
+
+void GWN_vertbuf_attr_fill(Gwn_VertBuf* verts, unsigned a_idx, const void* data)
+ {
+ const Gwn_VertFormat* format = &verts->format;
+ const Gwn_VertAttr* a = format->attribs + a_idx;
+
+#if TRUST_NO_ONE
+ assert(a_idx < format->attrib_ct);
+#endif
+
+ const unsigned stride = a->sz; // tightly packed input data
+
+ GWN_vertbuf_attr_fill_stride(verts, a_idx, stride, data);
+ }
+
+void GWN_vertbuf_attr_fill_stride(Gwn_VertBuf* verts, unsigned a_idx, unsigned stride, const void* data)
+ {
+ const Gwn_VertFormat* format = &verts->format;
+ const Gwn_VertAttr* a = format->attribs + a_idx;
+
+#if TRUST_NO_ONE
+ assert(a_idx < format->attrib_ct);
+ assert(verts->data != NULL); // data must be in main mem
+#endif
+
+ const unsigned vertex_ct = verts->vertex_ct;
+
+ if (format->attrib_ct == 1 && stride == format->stride)
+ {
+ // we can copy it all at once
+ memcpy(verts->data, data, vertex_ct * a->sz);
+ }
+ else
+ {
+ // we must copy it per vertex
+ for (unsigned v = 0; v < vertex_ct; ++v)
+ memcpy((GLubyte*)verts->data + a->offset + v * format->stride, (const GLubyte*)data + v * stride, a->sz);
+ }
+ }
+
+void GWN_vertbuf_attr_get_raw_data(Gwn_VertBuf* verts, unsigned a_idx, Gwn_VertBufRaw *access)
+ {
+ const Gwn_VertFormat* format = &verts->format;
+ const Gwn_VertAttr* a = format->attribs + a_idx;
+
+#if TRUST_NO_ONE
+ assert(a_idx < format->attrib_ct);
+ assert(verts->data != NULL); // data must be in main mem
+#endif
+
+ access->size = a->sz;
+ access->stride = format->stride;
+ access->data = (GLubyte*)verts->data + a->offset;
+ access->data_init = access->data;
+#if TRUST_NO_ONE
+ access->_data_end = access->data_init + (size_t)(verts->vertex_ct * format->stride);
+#endif
+ }
+
+
+static void VertexBuffer_prime(Gwn_VertBuf* verts)
+ {
+ const unsigned buffer_sz = GWN_vertbuf_size_get(verts);
+
+ verts->vbo_id = GWN_buf_id_alloc();
+ glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id);
+ // fill with delicious data & send to GPU the first time only
+ glBufferData(GL_ARRAY_BUFFER, buffer_sz, verts->data, GL_STATIC_DRAW);
+
+ vbo_memory_usage += buffer_sz;
+
+#if KEEP_SINGLE_COPY
+ // now that GL has a copy, discard original
+ free(verts->data);
+ verts->data = NULL;
+#endif
+ }
+
+void GWN_vertbuf_use(Gwn_VertBuf* verts)
+ {
+ if (verts->vbo_id)
+ glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id);
+ else
+ VertexBuffer_prime(verts);
+ }
+
+unsigned GWN_vertbuf_get_memory_usage(void)
+ {
+ return vbo_memory_usage;
+ }
diff --git a/intern/gawain/src/vertex_format.c b/intern/gawain/src/vertex_format.c
new file mode 100644
index 00000000000..34704db3359
--- /dev/null
+++ b/intern/gawain/src/vertex_format.c
@@ -0,0 +1,296 @@
+
+// Gawain vertex format
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#include "vertex_format.h"
+#include "vertex_format_private.h"
+#include <stddef.h>
+#include <string.h>
+
+#define PACK_DEBUG 0
+
+#if PACK_DEBUG
+ #include <stdio.h>
+#endif
+
+void GWN_vertformat_clear(Gwn_VertFormat* format)
+ {
+#if TRUST_NO_ONE
+ memset(format, 0, sizeof(Gwn_VertFormat));
+#else
+ format->attrib_ct = 0;
+ format->packed = false;
+ format->name_offset = 0;
+ format->name_ct = 0;
+
+ for (unsigned i = 0; i < GWN_VERT_ATTR_MAX_LEN; i++)
+ {
+ format->attribs[i].name_ct = 0;
+ }
+#endif
+ }
+
+void GWN_vertformat_copy(Gwn_VertFormat* dest, const Gwn_VertFormat* src)
+ {
+ // copy regular struct fields
+ memcpy(dest, src, sizeof(Gwn_VertFormat));
+
+ for (unsigned i = 0; i < dest->attrib_ct; i++)
+ {
+ dest->attribs[i].name_ct = dest->attribs[i].name_ct;
+ for (unsigned j = 0; j < dest->attribs[i].name_ct; j++)
+ {
+ dest->attribs[i].name[j] = (char *)dest + (src->attribs[i].name[j] - ((char *)src));
+ }
+ }
+ }
+
+static GLenum convert_comp_type_to_gl(Gwn_VertCompType type)
+ {
+ static const GLenum table[] = {
+ [GWN_COMP_I8] = GL_BYTE,
+ [GWN_COMP_U8] = GL_UNSIGNED_BYTE,
+ [GWN_COMP_I16] = GL_SHORT,
+ [GWN_COMP_U16] = GL_UNSIGNED_SHORT,
+ [GWN_COMP_I32] = GL_INT,
+ [GWN_COMP_U32] = GL_UNSIGNED_INT,
+
+ [GWN_COMP_F32] = GL_FLOAT,
+
+ [GWN_COMP_I10] = GL_INT_2_10_10_10_REV
+ };
+ return table[type];
+ }
+
+static unsigned comp_sz(Gwn_VertCompType type)
+ {
+#if TRUST_NO_ONE
+ assert(type <= GWN_COMP_F32); // other types have irregular sizes (not bytes)
+#endif
+
+ const GLubyte sizes[] = {1,1,2,2,4,4,4};
+ return sizes[type];
+ }
+
+static unsigned attrib_sz(const Gwn_VertAttr *a)
+ {
+ if (a->comp_type == GWN_COMP_I10)
+ return 4; // always packed as 10_10_10_2
+
+ return a->comp_ct * comp_sz(a->comp_type);
+ }
+
+static unsigned attrib_align(const Gwn_VertAttr *a)
+ {
+ if (a->comp_type == GWN_COMP_I10)
+ return 4; // always packed as 10_10_10_2
+
+ unsigned c = comp_sz(a->comp_type);
+ if (a->comp_ct == 3 && c <= 2)
+ return 4 * c; // AMD HW can't fetch these well, so pad it out (other vendors too?)
+ else
+ return c; // most fetches are ok if components are naturally aligned
+ }
+
+unsigned vertex_buffer_size(const Gwn_VertFormat* format, unsigned vertex_ct)
+ {
+#if TRUST_NO_ONE
+ assert(format->packed && format->stride > 0);
+#endif
+
+ return format->stride * vertex_ct;
+ }
+
+static const char* copy_attrib_name(Gwn_VertFormat* format, const char* name)
+ {
+ // strncpy does 110% of what we need; let's do exactly 100%
+ char* name_copy = format->names + format->name_offset;
+ unsigned available = GWN_VERT_ATTR_NAMES_BUF_LEN - format->name_offset;
+ bool terminated = false;
+
+ for (unsigned i = 0; i < available; ++i)
+ {
+ const char c = name[i];
+ name_copy[i] = c;
+ if (c == '\0')
+ {
+ terminated = true;
+ format->name_offset += (i + 1);
+ break;
+ }
+ }
+
+#if TRUST_NO_ONE
+ assert(terminated);
+ assert(format->name_offset <= GWN_VERT_ATTR_NAMES_BUF_LEN);
+#else
+ (void)terminated;
+#endif
+
+ return name_copy;
+ }
+
+unsigned GWN_vertformat_attr_add(Gwn_VertFormat* format, const char* name, Gwn_VertCompType comp_type, unsigned comp_ct, Gwn_VertFetchMode fetch_mode)
+ {
+#if TRUST_NO_ONE
+ assert(format->name_ct < GWN_VERT_ATTR_MAX_LEN); // there's room for more
+ assert(format->attrib_ct < GWN_VERT_ATTR_MAX_LEN); // there's room for more
+ assert(!format->packed); // packed means frozen/locked
+ assert(comp_ct >= 1 && comp_ct <= 4);
+ switch (comp_type)
+ {
+ case GWN_COMP_F32:
+ // float type can only kept as float
+ assert(fetch_mode == GWN_FETCH_FLOAT);
+ break;
+ case GWN_COMP_I10:
+ // 10_10_10 format intended for normals (xyz) or colors (rgb)
+ // extra component packed.w can be manually set to { -2, -1, 0, 1 }
+ assert(comp_ct == 3 || comp_ct == 4);
+ assert(fetch_mode == GWN_FETCH_INT_TO_FLOAT_UNIT); // not strictly required, may relax later
+ break;
+ default:
+ // integer types can be kept as int or converted/normalized to float
+ assert(fetch_mode != GWN_FETCH_FLOAT);
+ }
+#endif
+ format->name_ct++; // multiname support
+
+ const unsigned attrib_id = format->attrib_ct++;
+ Gwn_VertAttr* attrib = format->attribs + attrib_id;
+
+ attrib->name[attrib->name_ct++] = copy_attrib_name(format, name);
+ attrib->comp_type = comp_type;
+ attrib->gl_comp_type = convert_comp_type_to_gl(comp_type);
+ attrib->comp_ct = (comp_type == GWN_COMP_I10) ? 4 : comp_ct; // system needs 10_10_10_2 to be 4 or BGRA
+ attrib->sz = attrib_sz(attrib);
+ attrib->offset = 0; // offsets & stride are calculated later (during pack)
+ attrib->fetch_mode = fetch_mode;
+
+ return attrib_id;
+ }
+
+void GWN_vertformat_alias_add(Gwn_VertFormat* format, const char* alias)
+ {
+ Gwn_VertAttr* attrib = format->attribs + (format->attrib_ct - 1);
+#if TRUST_NO_ONE
+ assert(format->name_ct < GWN_VERT_ATTR_MAX_LEN); // there's room for more
+ assert(attrib->name_ct < MAX_ATTRIB_NAMES);
+#endif
+ format->name_ct++; // multiname support
+ attrib->name[attrib->name_ct++] = copy_attrib_name(format, alias);
+ }
+
+unsigned padding(unsigned offset, unsigned alignment)
+ {
+ const unsigned mod = offset % alignment;
+ return (mod == 0) ? 0 : (alignment - mod);
+ }
+
+#if PACK_DEBUG
+static void show_pack(unsigned a_idx, unsigned sz, unsigned pad)
+ {
+ const char c = 'A' + a_idx;
+ for (unsigned i = 0; i < pad; ++i)
+ putchar('-');
+ for (unsigned i = 0; i < sz; ++i)
+ putchar(c);
+ }
+#endif
+
+void VertexFormat_pack(Gwn_VertFormat* format)
+ {
+ // for now, attributes are packed in the order they were added,
+ // making sure each attrib is naturally aligned (add padding where necessary)
+
+ // later we can implement more efficient packing w/ reordering
+ // (keep attrib ID order, adjust their offsets to reorder in buffer)
+
+ // TODO:
+ // realloc just enough to hold the final combo string. And just enough to
+ // hold used attribs, not all 16.
+
+ Gwn_VertAttr* a0 = format->attribs + 0;
+ a0->offset = 0;
+ unsigned offset = a0->sz;
+
+#if PACK_DEBUG
+ show_pack(0, a0->sz, 0);
+#endif
+
+ for (unsigned a_idx = 1; a_idx < format->attrib_ct; ++a_idx)
+ {
+ Gwn_VertAttr* a = format->attribs + a_idx;
+ unsigned mid_padding = padding(offset, attrib_align(a));
+ offset += mid_padding;
+ a->offset = offset;
+ offset += a->sz;
+
+#if PACK_DEBUG
+ show_pack(a_idx, a->sz, mid_padding);
+#endif
+ }
+
+ unsigned end_padding = padding(offset, attrib_align(a0));
+
+#if PACK_DEBUG
+ show_pack(0, 0, end_padding);
+ putchar('\n');
+#endif
+
+ format->stride = offset + end_padding;
+ format->packed = true;
+ }
+
+
+// OpenGL ES packs in a different order as desktop GL but component conversion is the same.
+// Of the code here, only struct Gwn_PackedNormal needs to change.
+
+#define SIGNED_INT_10_MAX 511
+#define SIGNED_INT_10_MIN -512
+
+static int clampi(int x, int min_allowed, int max_allowed)
+ {
+#if TRUST_NO_ONE
+ assert(min_allowed <= max_allowed);
+#endif
+
+ if (x < min_allowed)
+ return min_allowed;
+ else if (x > max_allowed)
+ return max_allowed;
+ else
+ return x;
+ }
+
+static int quantize(float x)
+ {
+ int qx = x * 511.0f;
+ return clampi(qx, SIGNED_INT_10_MIN, SIGNED_INT_10_MAX);
+ }
+
+static int convert_i16(short x)
+ {
+ // 16-bit signed --> 10-bit signed
+ return x >> 6;
+ // TODO: round?
+ }
+
+Gwn_PackedNormal GWN_normal_convert_i10_v3(const float data[3])
+ {
+ Gwn_PackedNormal n = { .x = quantize(data[0]), .y = quantize(data[1]), .z = quantize(data[2]) };
+ return n;
+ }
+
+Gwn_PackedNormal GWN_normal_convert_i10_s3(const short data[3])
+ {
+ Gwn_PackedNormal n = { .x = convert_i16(data[0]), .y = convert_i16(data[1]), .z = convert_i16(data[2]) };
+ return n;
+ }
diff --git a/intern/ghost/intern/GHOST_Context.cpp b/intern/ghost/intern/GHOST_Context.cpp
index 72db17c4f56..823a476d244 100644
--- a/intern/ghost/intern/GHOST_Context.cpp
+++ b/intern/ghost/intern/GHOST_Context.cpp
@@ -143,11 +143,7 @@ bool win32_chk(bool result, const char *file, int line, const char *text)
void GHOST_Context::initContextGLEW()
{
- mxDestroyContext(m_mxContext); // no-op if m_mxContext is NULL
-
- mxMakeCurrentContext(mxCreateContext());
-
- m_mxContext = mxGetCurrentContext();
+ GLEW_CHK(glewInit());
}
diff --git a/intern/ghost/intern/GHOST_Context.h b/intern/ghost/intern/GHOST_Context.h
index 18d36c40e9c..8776fa4764f 100644
--- a/intern/ghost/intern/GHOST_Context.h
+++ b/intern/ghost/intern/GHOST_Context.h
@@ -50,15 +50,13 @@ public:
*/
GHOST_Context(bool stereoVisual, GHOST_TUns16 numOfAASamples)
: m_stereoVisual(stereoVisual),
- m_numOfAASamples(numOfAASamples),
- m_mxContext(NULL)
+ m_numOfAASamples(numOfAASamples)
{}
/**
* Destructor.
*/
virtual ~GHOST_Context() {
- mxDestroyContext(m_mxContext);
}
/**
@@ -128,19 +126,12 @@ public:
protected:
void initContextGLEW();
- inline void activateGLEW() const {
- mxMakeCurrentContext(m_mxContext);
- }
-
bool m_stereoVisual;
GHOST_TUns16 m_numOfAASamples;
static void initClearGL();
-private:
- MXContext *m_mxContext;
-
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_Context")
#endif
diff --git a/intern/ghost/intern/GHOST_ContextCGL.h b/intern/ghost/intern/GHOST_ContextCGL.h
index dd49b81b561..6dcc4da0f0a 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.h
+++ b/intern/ghost/intern/GHOST_ContextCGL.h
@@ -34,10 +34,6 @@
#include "GHOST_Context.h"
-//#define cglewGetContext() cglewContext
-//#include <GL/cglew.h>
-//extern "C" CGLEWContext *cglewContext;
-
#ifndef GHOST_OPENGL_CGL_CONTEXT_FLAGS
#define GHOST_OPENGL_CGL_CONTEXT_FLAGS 0
#endif
@@ -120,21 +116,14 @@ public:
*/
GHOST_TSuccess updateDrawingContext();
-//protected:
-// inline void activateCGLEW() const {
-// cglewContext = m_cglewContext;
-// }
-
private:
- //void initContextCGLEW()
-
/** The openGL view */
NSOpenGLView *m_openGLView;
/** The OpenGL drawing context */
NSOpenGLContext *m_openGLContext;
- //static CGLEWContext *s_cglewContext;
+ bool m_coreProfile;
const bool m_debug;
diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm
index 03c45f9945b..03af3cc497e 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.mm
+++ b/intern/ghost/intern/GHOST_ContextCGL.mm
@@ -63,6 +63,23 @@ GHOST_ContextCGL::GHOST_ContextCGL(
m_debug(contextFlags)
{
assert(openGLView != nil);
+
+ // for now be very strict about OpenGL version requested
+ switch (contextMajorVersion) {
+ case 2:
+ assert(contextMinorVersion == 1);
+ assert(contextProfileMask == 0);
+ m_coreProfile = false;
+ break;
+ case 3:
+ // Apple didn't implement 3.0 or 3.1
+ assert(contextMinorVersion == 2);
+ assert(contextProfileMask == GL_CONTEXT_CORE_PROFILE_BIT);
+ m_coreProfile = true;
+ break;
+ default:
+ assert(false);
+ }
}
@@ -142,9 +159,6 @@ GHOST_TSuccess GHOST_ContextCGL::activateDrawingContext()
if (m_openGLContext != nil) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[m_openGLContext makeCurrentContext];
-
- activateGLEW();
-
[pool drain];
return GHOST_kSuccess;
}
@@ -170,6 +184,7 @@ GHOST_TSuccess GHOST_ContextCGL::updateDrawingContext()
static void makeAttribList(
std::vector<NSOpenGLPixelFormatAttribute>& attribs,
+ bool coreProfile,
bool stereoVisual,
int numOfAASamples,
bool needAlpha,
@@ -178,6 +193,9 @@ static void makeAttribList(
{
attribs.clear();
+ attribs.push_back(NSOpenGLPFAOpenGLProfile);
+ attribs.push_back(coreProfile ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy);
+
// Pixel Format Attributes for the windowed NSOpenGLContext
attribs.push_back(NSOpenGLPFADoubleBuffer);
@@ -190,15 +208,11 @@ static void makeAttribList(
attribs.push_back(NSOpenGLPFANoRecovery);
}
- /* Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway */
- //attribs.push_back(NSOpenGLPFAAllowOfflineRenderers);
+ attribs.push_back(NSOpenGLPFAAllowOfflineRenderers); // for automatic GPU switching
attribs.push_back(NSOpenGLPFADepthSize);
attribs.push_back((NSOpenGLPixelFormatAttribute) 32);
- attribs.push_back(NSOpenGLPFAAccumSize);
- attribs.push_back((NSOpenGLPixelFormatAttribute) 32);
-
if (stereoVisual)
attribs.push_back(NSOpenGLPFAStereo);
@@ -263,7 +277,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
NSOpenGLPixelFormat *pixelFormat;
// TODO: keep pixel format for subsequent windows/contexts instead of recreating each time
- makeAttribList(attribs, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, softwareGL);
+ makeAttribList(attribs, m_coreProfile, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, softwareGL);
pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]];
@@ -274,7 +288,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
// (Now that I think about it, does WGL really require the code that it has for finding a lesser match?)
attribs.clear();
- makeAttribList(attribs, m_stereoVisual, 0, needAlpha, needStencil, softwareGL);
+ makeAttribList(attribs, m_coreProfile, m_stereoVisual, 0, needAlpha, needStencil, softwareGL);
pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]];
}
@@ -316,7 +330,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
[m_openGLContext release];
// create software GL context
- makeAttribList(attribs, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, softwareGL);
+ makeAttribList(attribs, m_coreProfile, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, softwareGL);
pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]];
m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:s_sharedOpenGLContext];
[pixelFormat release];
diff --git a/intern/ghost/intern/GHOST_ContextEGL.cpp b/intern/ghost/intern/GHOST_ContextEGL.cpp
index 520aa0fffb2..a591d9b7583 100644
--- a/intern/ghost/intern/GHOST_ContextEGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextEGL.cpp
@@ -42,11 +42,6 @@
#include <cstring>
-#ifdef WITH_GLEW_MX
-EGLEWContext *eglewContext = NULL;
-#endif
-
-
#define CASE_CODE_RETURN_STR(code) case code: return #code;
static const char *get_egl_error_enum_string(EGLenum error)
@@ -168,13 +163,8 @@ static bool egl_chk(bool result, const char *file = NULL, int line = 0, const ch
static inline bool bindAPI(EGLenum api)
{
-#ifdef WITH_GLEW_MX
- if (eglewContext != NULL)
-#endif
- {
- if (EGLEW_VERSION_1_2) {
- return (EGL_CHK(eglBindAPI(api)) == EGL_TRUE);
- }
+ if (EGLEW_VERSION_1_2) {
+ return (EGL_CHK(eglBindAPI(api)) == EGL_TRUE);
}
return false;
@@ -238,9 +228,6 @@ GHOST_ContextEGL::GHOST_ContextEGL(
m_surface(EGL_NO_SURFACE),
m_display(EGL_NO_DISPLAY),
m_swap_interval(1),
-#ifdef WITH_GLEW_MX
- m_eglewContext(NULL),
-#endif
m_sharedContext(choose_api(api, s_gl_sharedContext, s_gles_sharedContext, s_vg_sharedContext)),
m_sharedCount (choose_api(api, s_gl_sharedCount, s_gles_sharedCount, s_vg_sharedCount))
{
@@ -252,7 +239,6 @@ GHOST_ContextEGL::GHOST_ContextEGL(
GHOST_ContextEGL::~GHOST_ContextEGL()
{
if (m_display != EGL_NO_DISPLAY) {
- activateEGLEW();
bindAPI(m_api);
@@ -276,10 +262,6 @@ GHOST_ContextEGL::~GHOST_ContextEGL()
EGL_CHK(::eglDestroySurface(m_display, m_surface));
EGL_CHK(::eglTerminate(m_display));
-
-#ifdef WITH_GLEW_MX
- delete m_eglewContext;
-#endif
}
}
@@ -321,9 +303,6 @@ GHOST_TSuccess GHOST_ContextEGL::getSwapInterval(int &intervalOut)
GHOST_TSuccess GHOST_ContextEGL::activateDrawingContext()
{
if (m_display) {
- activateEGLEW();
- activateGLEW();
-
bindAPI(m_api);
return EGL_CHK(::eglMakeCurrent(m_display, m_surface, m_surface, m_context)) ? GHOST_kSuccess : GHOST_kFailure;
@@ -336,14 +315,6 @@ GHOST_TSuccess GHOST_ContextEGL::activateDrawingContext()
void GHOST_ContextEGL::initContextEGLEW()
{
-#ifdef WITH_GLEW_MX
- eglewContext = new EGLEWContext;
- memset(eglewContext, 0, sizeof(EGLEWContext));
-
- delete m_eglewContext;
- m_eglewContext = eglewContext;
-#endif
-
if (GLEW_CHK(eglewInit(m_display)) != GLEW_OK)
fprintf(stderr, "Warning! EGLEW failed to initialize properly.\n");
}
diff --git a/intern/ghost/intern/GHOST_ContextEGL.h b/intern/ghost/intern/GHOST_ContextEGL.h
index 70c26c940fc..6dfb177f26d 100644
--- a/intern/ghost/intern/GHOST_ContextEGL.h
+++ b/intern/ghost/intern/GHOST_ContextEGL.h
@@ -34,17 +34,8 @@
#include "GHOST_Context.h"
-#ifdef WITH_GLEW_MX
-# define eglewGetContext() eglewContext
-#endif
-
#include <GL/eglew.h>
-#ifdef WITH_GLEW_MX
-extern "C" EGLEWContext *eglewContext;
-#endif
-
-
#ifndef GHOST_OPENGL_EGL_CONTEXT_FLAGS
#define GHOST_OPENGL_EGL_CONTEXT_FLAGS 0
#endif
@@ -116,13 +107,6 @@ public:
*/
GHOST_TSuccess getSwapInterval(int &intervalOut);
-protected:
- inline void activateEGLEW() const {
-#ifdef WITH_GLEW_MX
- eglewContext = m_eglewContext;
-#endif
- }
-
private:
void initContextEGLEW();
@@ -143,10 +127,6 @@ private:
EGLint m_swap_interval;
-#ifdef WITH_GLEW_MX
- EGLEWContext *m_eglewContext;
-#endif
-
EGLContext &m_sharedContext;
EGLint &m_sharedCount;
diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp
index 9ac61db4041..0a9dc900aed 100644
--- a/intern/ghost/intern/GHOST_ContextGLX.cpp
+++ b/intern/ghost/intern/GHOST_ContextGLX.cpp
@@ -48,10 +48,6 @@ static GLuint _glewStrLen(const GLubyte *s);
static GLboolean _glewSearchExtension(const char *name, const GLubyte *start, const GLubyte *end);
#endif
-#ifdef WITH_GLEW_MX
-GLXEWContext *glxewContext = NULL;
-#endif
-
GLXContext GHOST_ContextGLX::s_sharedContext = None;
int GHOST_ContextGLX::s_sharedCount = 0;
@@ -79,10 +75,6 @@ GHOST_ContextGLX::GHOST_ContextGLX(
m_contextFlags(contextFlags),
m_contextResetNotificationStrategy(contextResetNotificationStrategy),
m_context(None)
-#ifdef WITH_GLEW_MX
- ,
- m_glxewContext(NULL)
-#endif
{
assert(m_window != 0);
assert(m_display != NULL);
@@ -92,8 +84,6 @@ GHOST_ContextGLX::GHOST_ContextGLX(
GHOST_ContextGLX::~GHOST_ContextGLX()
{
if (m_display != NULL) {
- activateGLXEW();
-
if (m_context != None) {
if (m_window != 0 && m_context == ::glXGetCurrentContext())
::glXMakeCurrent(m_display, None, NULL);
@@ -109,11 +99,6 @@ GHOST_ContextGLX::~GHOST_ContextGLX()
::glXDestroyContext(m_display, m_context);
}
}
-
-#ifdef WITH_GLEW_MX
- if (m_glxewContext)
- delete m_glxewContext;
-#endif
}
}
@@ -129,9 +114,6 @@ GHOST_TSuccess GHOST_ContextGLX::swapBuffers()
GHOST_TSuccess GHOST_ContextGLX::activateDrawingContext()
{
if (m_display) {
- activateGLXEW();
- activateGLEW();
-
return ::glXMakeCurrent(m_display, m_window, m_context) ? GHOST_kSuccess : GHOST_kFailure;
}
else {
@@ -141,15 +123,6 @@ GHOST_TSuccess GHOST_ContextGLX::activateDrawingContext()
void GHOST_ContextGLX::initContextGLXEW()
{
-#ifdef WITH_GLEW_MX
- glxewContext = new GLXEWContext;
- memset(glxewContext, 0, sizeof(GLXEWContext));
-
- if (m_glxewContext)
- delete m_glxewContext;
- m_glxewContext = glxewContext;
-#endif
-
initContextGLEW();
}
@@ -255,9 +228,6 @@ const bool GLXEW_ARB_create_context_robustness =
if (m_contextMajorVersion != 0) {
attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
attribs[i++] = m_contextMajorVersion;
- }
-
- if (m_contextMinorVersion != 0) {
attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB;
attribs[i++] = m_contextMinorVersion;
}
@@ -300,8 +270,8 @@ const bool GLXEW_ARB_create_context_robustness =
}
}
else {
- /* Create legacy context */
- m_context = glXCreateContext(m_display, m_visualInfo, s_sharedContext, True);
+ /* Don't create legacy context */
+ fprintf(stderr, "Warning! GLX_ARB_create_context not available.\n");
}
GHOST_TSuccess success;
@@ -328,8 +298,14 @@ const bool GLXEW_ARB_create_context_robustness =
version = glGetString(GL_VERSION);
- if (!version || version[0] < '2' || ((version[0] == '2') && (version[2] < '1'))) {
- fprintf(stderr, "Error! Blender requires OpenGL 2.1 to run. Try updating your drivers.\n");
+#if 0 // enable this when Blender switches to 3.3 core profile
+ if (!version || version[0] < '3' || ((version[0] == '3') && (version[2] < '3'))) {
+ fprintf(stderr, "Error! Blender requires OpenGL 3.3 to run. Try updating your drivers.\n");
+#else
+ // with Mesa, the closest thing to 3.3 compatibility profile is 3.0
+ if (!version || version[0] < '3') {
+ fprintf(stderr, "Error! Blender requires OpenGL 3.0 (soon 3.3) to run. Try updating your drivers.\n");
+#endif
fflush(stderr);
/* ugly, but we get crashes unless a whole bunch of systems are patched. */
exit(0);
diff --git a/intern/ghost/intern/GHOST_ContextGLX.h b/intern/ghost/intern/GHOST_ContextGLX.h
index f0f010d1942..6547a0bd00a 100644
--- a/intern/ghost/intern/GHOST_ContextGLX.h
+++ b/intern/ghost/intern/GHOST_ContextGLX.h
@@ -34,16 +34,8 @@
#include "GHOST_Context.h"
-#ifdef WITH_GLEW_MX
-# define glxewGetContext() glxewContext
-#endif
-
#include <GL/glxew.h>
-#ifdef WITH_GLEW_MX
-extern "C" GLXEWContext *glxewContext;
-#endif
-
#ifndef GHOST_OPENGL_GLX_CONTEXT_FLAGS
/* leave as convenience define for the future */
@@ -117,13 +109,6 @@ public:
*/
GHOST_TSuccess getSwapInterval(int &intervalOut);
-protected:
- inline void activateGLXEW() const {
-#ifdef WITH_GLEW_MX
- glxewContext = m_glxewContext;
-#endif
- }
-
private:
void initContextGLXEW();
@@ -140,10 +125,6 @@ private:
GLXContext m_context;
-#ifdef WITH_GLEW_MX
- GLXEWContext *m_glxewContext;
-#endif
-
/** The first created OpenGL context (for sharing display lists) */
static GLXContext s_sharedContext;
static int s_sharedCount;
diff --git a/intern/ghost/intern/GHOST_ContextSDL.cpp b/intern/ghost/intern/GHOST_ContextSDL.cpp
index 39627fac899..7a02e9743c3 100644
--- a/intern/ghost/intern/GHOST_ContextSDL.cpp
+++ b/intern/ghost/intern/GHOST_ContextSDL.cpp
@@ -97,8 +97,6 @@ GHOST_TSuccess GHOST_ContextSDL::swapBuffers()
GHOST_TSuccess GHOST_ContextSDL::activateDrawingContext()
{
if (m_context) {
- activateGLEW();
-
return SDL_GL_MakeCurrent(m_window, m_context) ? GHOST_kSuccess : GHOST_kFailure;
}
else {
diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp
index 64ee692797b..d2dd38878f7 100644
--- a/intern/ghost/intern/GHOST_ContextWGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextWGL.cpp
@@ -40,10 +40,6 @@
#include <vector>
-#ifdef WITH_GLEW_MX
-WGLEWContext *wglewContext = NULL;
-#endif
-
HGLRC GHOST_ContextWGL::s_sharedHGLRC = NULL;
int GHOST_ContextWGL::s_sharedCount = 0;
@@ -82,10 +78,6 @@ GHOST_ContextWGL::GHOST_ContextWGL(
m_alphaBackground(alphaBackground),
m_contextResetNotificationStrategy(contextResetNotificationStrategy),
m_hGLRC(NULL)
-#ifdef WITH_GLEW_MX
- ,
- m_wglewContext(NULL)
-#endif
#ifndef NDEBUG
,
m_dummyVendor(NULL),
@@ -116,10 +108,6 @@ GHOST_ContextWGL::~GHOST_ContextWGL()
}
}
-#ifdef WITH_GLEW_MX
- delete m_wglewContext;
-#endif
-
#ifndef NDEBUG
free((void*)m_dummyRenderer);
free((void*)m_dummyVendor);
@@ -158,7 +146,6 @@ GHOST_TSuccess GHOST_ContextWGL::getSwapInterval(int &intervalOut)
GHOST_TSuccess GHOST_ContextWGL::activateDrawingContext()
{
if (WIN32_CHK(::wglMakeCurrent(m_hDC, m_hGLRC))) {
- activateGLEW();
return GHOST_kSuccess;
}
else {
@@ -338,15 +325,6 @@ void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD)
int iPixelFormat;
-
-#ifdef WITH_GLEW_MX
- wglewContext = new WGLEWContext;
- memset(wglewContext, 0, sizeof(WGLEWContext));
-
- delete m_wglewContext;
- m_wglewContext = wglewContext;
-#endif
-
SetLastError(NO_ERROR);
prevHDC = ::wglGetCurrentDC();
@@ -385,13 +363,8 @@ void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD)
if (!WIN32_CHK(::wglMakeCurrent(dummyHDC, dummyHGLRC)))
goto finalize;
-#ifdef WITH_GLEW_MX
- if (GLEW_CHK(wglewInit()) != GLEW_OK)
- fprintf(stderr, "Warning! WGLEW failed to initialize properly.\n");
-#else
if (GLEW_CHK(glewInit()) != GLEW_OK)
fprintf(stderr, "Warning! Dummy GLEW/WGLEW failed to initialize properly.\n");
-#endif
// the following are not technially WGLEW, but they also require a context to work
@@ -828,8 +801,6 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
return GHOST_kFailure;
}
- activateWGLEW();
-
if (WGLEW_ARB_create_context) {
int profileBitCore = m_contextProfileMask & WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
int profileBitCompat = m_contextProfileMask & WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
@@ -907,21 +878,6 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
else
m_hGLRC = s_sharedHGLRC;
}
- else {
- if (m_contextProfileMask != 0)
- fprintf(stderr, "Warning! Legacy WGL is unable to select between OpenGL profiles.");
-
- if (m_contextMajorVersion != 0 || m_contextMinorVersion != 0)
- fprintf(stderr, "Warning! Legacy WGL is unable to select between OpenGL versions.");
-
- if (m_contextFlags != 0)
- fprintf(stderr, "Warning! Legacy WGL is unable to set context flags.");
-
- if (!s_singleContextMode || s_sharedHGLRC == NULL)
- m_hGLRC = ::wglCreateContext(m_hDC);
- else
- m_hGLRC = s_sharedHGLRC;
- }
if (!WIN32_CHK(m_hGLRC != NULL)) {
::wglMakeCurrent(prevHDC, prevHGLRC);
@@ -958,29 +914,6 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
reportContextString("Version", m_dummyVersion, version);
#endif
- if ((strcmp(vendor, "Microsoft Corporation") == 0 ||
- strcmp(renderer, "GDI Generic") == 0) && version[0] == '1' && version[2] == '1')
- {
- MessageBox(m_hWnd, "Your system does not use 3D hardware acceleration.\n"
- "Blender requires a graphics driver with OpenGL 2.1 support.\n\n"
- "This may be caused by:\n"
- "* A missing or faulty graphics driver installation.\n"
- " Blender needs a graphics card driver to work correctly.\n"
- "* Accessing Blender through a remote connection.\n"
- "* Using Blender through a virtual machine.\n\n"
- "The program will now close.",
- "Blender - Can't detect 3D hardware accelerated Driver!",
- MB_OK | MB_ICONERROR);
- exit(0);
- }
- else if (version[0] < '2' || (version[0] == '2' && version[2] < '1')) {
- MessageBox(m_hWnd, "Blender requires a graphics driver with OpenGL 2.1 support.\n\n"
- "The program will now close.",
- "Blender - Unsupported Graphics Driver!",
- MB_OK | MB_ICONERROR);
- exit(0);
- }
-
return GHOST_kSuccess;
}
@@ -994,3 +927,97 @@ GHOST_TSuccess GHOST_ContextWGL::releaseNativeHandles()
return success;
}
+
+/**
+ * For any given HDC you may call SetPixelFormat once
+ *
+ * So we better try to get the correct OpenGL version in a new window altogether, in case it fails.
+ * (see https://msdn.microsoft.com/en-us/library/windows/desktop/dd369049(v=vs.85).aspx)
+ */
+static bool TryOpenGLVersion(
+ HWND hwnd,
+ bool wantStereoVisual,
+ bool wantAlphaBackground,
+ GHOST_TUns16 wantNumOfAASamples,
+ int contextProfileMask,
+ bool debugContext,
+ int major, int minor)
+{
+ HWND dummyHWND = clone_window(hwnd, NULL);
+ if (dummyHWND == NULL) {
+ return false;
+ }
+
+ HDC dummyHDC = GetDC(dummyHWND);
+ if (dummyHDC == NULL) {
+ return false;
+ }
+
+ GHOST_ContextWGL * context = new GHOST_ContextWGL(
+ wantStereoVisual,
+ wantAlphaBackground,
+ wantNumOfAASamples,
+ dummyHWND,
+ dummyHDC,
+ contextProfileMask,
+ major, minor,
+ (debugContext ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
+ GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
+
+ bool result = context->initializeDrawingContext();
+ delete context;
+
+ ReleaseDC(dummyHWND, dummyHDC);
+ DestroyWindow(dummyHWND);
+
+ return result;
+}
+
+GHOST_TSuccess GHOST_ContextWGL::getMaximumSupportedOpenGLVersion(
+ HWND hwnd,
+ bool wantStereoVisual,
+ bool wantAlphaBackground,
+ GHOST_TUns16 wantNumOfAASamples,
+ int contextProfileMask,
+ bool debugContext,
+ GHOST_TUns8 *r_major_version,
+ GHOST_TUns8 *r_minor_version)
+{
+ /* - AMD and Intel give us exactly this version
+ * - NVIDIA gives at least this version <-- desired behavior
+ * So we ask for 4.5, 4.4 ... 3.3 in descending order to get the best version on the user's system. */
+ for (int minor = 5; minor >= 0; --minor) {
+ if (TryOpenGLVersion(
+ hwnd,
+ wantStereoVisual,
+ wantAlphaBackground,
+ wantNumOfAASamples,
+ contextProfileMask,
+ debugContext,
+ 4, minor))
+ {
+ *r_major_version = 4;
+ *r_minor_version = minor;
+ return GHOST_kSuccess;
+ }
+ }
+
+ /* Fallback to OpenGL 3.3 */
+ if (TryOpenGLVersion(
+ hwnd,
+ wantStereoVisual,
+ wantAlphaBackground,
+ wantNumOfAASamples,
+ contextProfileMask,
+ debugContext,
+ 3, 3))
+ {
+ *r_major_version = 3;
+ *r_minor_version = 3;
+ return GHOST_kSuccess;
+ }
+
+ *r_major_version = 0;
+ *r_minor_version = 0;
+ return GHOST_kFailure;
+}
diff --git a/intern/ghost/intern/GHOST_ContextWGL.h b/intern/ghost/intern/GHOST_ContextWGL.h
index 580b4dcb82f..0d9986a0802 100644
--- a/intern/ghost/intern/GHOST_ContextWGL.h
+++ b/intern/ghost/intern/GHOST_ContextWGL.h
@@ -36,24 +36,8 @@
#include "GHOST_Context.h"
-#ifdef WITH_GLEW_MX
-#define wglewGetContext() wglewContext
-#endif
-
#include <GL/wglew.h>
-#ifdef WITH_GLEW_MX
-extern "C" WGLEWContext *wglewContext;
-#endif
-
-#ifndef GHOST_OPENGL_WGL_CONTEXT_FLAGS
-# ifdef WITH_GPU_DEBUG
-# define GHOST_OPENGL_WGL_CONTEXT_FLAGS WGL_CONTEXT_DEBUG_BIT_ARB
-# else
-# define GHOST_OPENGL_WGL_CONTEXT_FLAGS 0
-# endif
-#endif
-
#ifndef GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY
#define GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY 0
#endif
@@ -121,12 +105,19 @@ public:
*/
GHOST_TSuccess getSwapInterval(int &intervalOut);
-protected:
- inline void activateWGLEW() const {
-#ifdef WITH_GLEW_MX
- wglewContext = m_wglewContext;
-#endif
- }
+ /**
+ * Gets the maximum supported OpenGL context for the user hardware
+ * \return Whether major_version and minor_version resulted in a valid context.
+ */
+ static GHOST_TSuccess getMaximumSupportedOpenGLVersion(
+ HWND hwnd,
+ bool wantStereoVisual,
+ bool wantAlphaBackground,
+ GHOST_TUns16 wantNumOfAASamples,
+ int contextProfileMask,
+ bool debugContext,
+ GHOST_TUns8 *r_major_version,
+ GHOST_TUns8 *r_minor_version);
private:
int choose_pixel_format(
@@ -171,10 +162,6 @@ private:
const int m_contextResetNotificationStrategy;
HGLRC m_hGLRC;
-
-#ifdef WITH_GLEW_MX
- WGLEWContext *m_wglewContext;
-#endif
#ifndef NDEBUG
const char *m_dummyVendor;
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index 73c89f9d68d..a018bbe15c6 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -1086,82 +1086,23 @@ GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order)
GHOST_Context *GHOST_WindowCocoa::newDrawingContext(GHOST_TDrawingContextType type)
{
if (type == GHOST_kDrawingContextTypeOpenGL) {
-#if !defined(WITH_GL_EGL)
-#if defined(WITH_GL_PROFILE_CORE)
- GHOST_Context *context = new GHOST_ContextCGL(
- m_wantStereoVisual,
- m_wantNumOfAASamples,
- m_window,
- m_openGLView,
- GL_CONTEXT_CORE_PROFILE_BIT,
- 3, 2,
- GHOST_OPENGL_CGL_CONTEXT_FLAGS,
- GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY);
-#elif defined(WITH_GL_PROFILE_ES20)
GHOST_Context *context = new GHOST_ContextCGL(
m_wantStereoVisual,
m_wantNumOfAASamples,
m_window,
m_openGLView,
- CGL_CONTEXT_ES2_PROFILE_BIT_EXT,
- 2, 0,
- GHOST_OPENGL_CGL_CONTEXT_FLAGS,
- GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY);
-#elif defined(WITH_GL_PROFILE_COMPAT)
- GHOST_Context *context = new GHOST_ContextCGL(
- m_wantStereoVisual,
- m_wantNumOfAASamples,
- m_window,
- m_openGLView,
- 0, // profile bit
- 0, 0,
- m_debug_context,
- GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY);
-#else
-# error
-#endif
-
-#else
#if defined(WITH_GL_PROFILE_CORE)
- GHOST_Context *context = new GHOST_ContextEGL(
- m_wantStereoVisual,
- m_wantNumOfAASamples,
- m_window,
- m_openGLView,
- EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
+ GL_CONTEXT_CORE_PROFILE_BIT,
3, 2,
- GHOST_OPENGL_EGL_CONTEXT_FLAGS,
- GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
- EGL_OPENGL_API);
-#elif defined(WITH_GL_PROFILE_ES20)
- GHOST_Context *context = new GHOST_ContextEGL(
- m_wantStereoVisual,
- m_wantNumOfAASamples,
- m_window,
- m_openGLView,
- 0, // profile bit
- 2, 0,
- GHOST_OPENGL_EGL_CONTEXT_FLAGS,
- GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
- EGL_OPENGL_ES_API);
-#elif defined(WITH_GL_PROFILE_COMPAT)
- GHOST_Context *context = new GHOST_ContextEGL(
- m_wantStereoVisual,
- m_wantNumOfAASamples,
- m_window,
- m_openGLView,
- 0, // profile bit
- 0, 0,
- GHOST_OPENGL_EGL_CONTEXT_FLAGS,
- GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
- EGL_OPENGL_API);
#else
-# error
+ 0, // no profile bit
+ 2, 1,
#endif
+ GHOST_OPENGL_CGL_CONTEXT_FLAGS,
+ GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY);
-#endif
if (context->initializeDrawingContext())
return context;
else
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 7ac54e5c915..fc4979291ec 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -611,101 +611,72 @@ GHOST_TSuccess GHOST_WindowWin32::invalidate()
GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType type)
{
if (type == GHOST_kDrawingContextTypeOpenGL) {
-#if !defined(WITH_GL_EGL)
+ GHOST_Context *context;
#if defined(WITH_GL_PROFILE_CORE)
- GHOST_Context *context = new GHOST_ContextWGL(
- m_wantStereoVisual,
- m_wantAlphaBackground,
- m_wantNumOfAASamples,
- m_hWnd,
- m_hDC,
- WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
- 3, 2,
- GHOST_OPENGL_WGL_CONTEXT_FLAGS,
- GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
-#elif defined(WITH_GL_PROFILE_ES20)
- GHOST_Context *context = new GHOST_ContextWGL(
- m_wantStereoVisual,
- m_wantAlphaBackground,
- m_wantNumOfAASamples,
- m_hWnd,
- m_hDC,
- WGL_CONTEXT_ES2_PROFILE_BIT_EXT,
- 2, 0,
- GHOST_OPENGL_WGL_CONTEXT_FLAGS,
- GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
+ GHOST_TUns8 major, minor;
+
+ if (GHOST_ContextWGL::getMaximumSupportedOpenGLVersion(
+ m_hWnd,
+ m_wantStereoVisual,
+ m_wantAlphaBackground,
+ m_wantNumOfAASamples,
+ WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
+ m_debug_context,
+ &major, &minor))
+ {
+ context = new GHOST_ContextWGL(
+ m_wantStereoVisual,
+ m_wantAlphaBackground,
+ m_wantNumOfAASamples,
+ m_hWnd,
+ m_hDC,
+ WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
+ major, minor,
+ (m_debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
+ GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
+
+ if (context->initializeDrawingContext()) {
+ return context;
+ }
+ else {
+ delete context;
+ }
+ }
+ else {
+ MessageBox(
+ m_hWnd,
+ "Blender requires a graphics driver with at least OpenGL 3.3 support.\n\n"
+ "The program will now close.",
+ "Blender - Unsupported Graphics Driver!",
+ MB_OK | MB_ICONERROR);
+ exit(0);
+ return NULL;
+ }
+
#elif defined(WITH_GL_PROFILE_COMPAT)
- GHOST_Context *context = new GHOST_ContextWGL(
+ // ask for 2.1 context, driver gives any GL version >= 2.1 (hopefully the latest compatibility profile)
+ // 2.1 ignores the profile bit & is incompatible with core profile
+ context = new GHOST_ContextWGL(
m_wantStereoVisual,
m_wantAlphaBackground,
m_wantNumOfAASamples,
m_hWnd,
m_hDC,
-#if 1
- 0, // profile bit
- 2, 1, // GL version requested
-#else
- // switch to this for Blender 2.8 development
- WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
- 3, 2,
-#endif
+ 0, // no profile bit
+ 2, 1,
(m_debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
#else
-# error
-#endif
-
-#else
-
-#if defined(WITH_GL_PROFILE_CORE)
- GHOST_Context *context = new GHOST_ContextEGL(
- m_wantStereoVisual,
- m_wantNumOfAASamples,
- m_hWnd,
- m_hDC,
- EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
- 3, 2,
- GHOST_OPENGL_EGL_CONTEXT_FLAGS,
- GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
- EGL_OPENGL_API);
-#elif defined(WITH_GL_PROFILE_ES20)
- GHOST_Context *context = new GHOST_ContextEGL(
- m_wantStereoVisual,
- m_wantNumOfAASamples,
- m_hWnd,
- m_hDC,
- 0, // profile bit
- 2, 0,
- GHOST_OPENGL_EGL_CONTEXT_FLAGS,
- GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
- EGL_OPENGL_ES_API);
-#elif defined(WITH_GL_PROFILE_COMPAT)
- GHOST_Context *context = new GHOST_ContextEGL(
- m_wantStereoVisual,
- m_wantNumOfAASamples,
- m_hWnd,
- m_hDC,
-#if 1
- 0, // profile bit
- 2, 1, // GL version requested
-#else
- // switch to this for Blender 2.8 development
- EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT,
- 3, 2,
-#endif
- GHOST_OPENGL_EGL_CONTEXT_FLAGS,
- GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
- EGL_OPENGL_API);
-#else
-# error
+# error // must specify either core or compat at build time
#endif
-#endif
- if (context->initializeDrawingContext())
+ if (context->initializeDrawingContext()) {
return context;
- else
+ }
+ else {
delete context;
+ }
}
return NULL;
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index 2019f58251f..450fe568814 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -1318,92 +1318,74 @@ GHOST_WindowX11::
GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type)
{
if (type == GHOST_kDrawingContextTypeOpenGL) {
-#if !defined(WITH_GL_EGL)
+
+ // During development:
+ // try 4.x compatibility profile
+ // try 3.3 compatibility profile
+ // fall back to 3.0 if needed
+ //
+ // Final Blender 2.8:
+ // try 4.x core profile
+ // try 3.3 core profile
+ // no fallbacks
#if defined(WITH_GL_PROFILE_CORE)
- GHOST_Context *context = new GHOST_ContextGLX(
- m_wantStereoVisual,
- m_wantNumOfAASamples,
- m_window,
- m_display,
- m_visualInfo,
- (GLXFBConfig)m_fbconfig,
- GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
- 3, 2,
- GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
- GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
-#elif defined(WITH_GL_PROFILE_ES20)
- GHOST_Context *context = new GHOST_ContextGLX(
- m_wantStereoVisual,
- m_wantNumOfAASamples,
- m_window,
- m_display,
- m_visualInfo,
- (GLXFBConfig)m_fbconfig,
- GLX_CONTEXT_ES2_PROFILE_BIT_EXT,
- 2, 0,
- GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
- GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
+ {
+ const char *version_major = (char*)glewGetString(GLEW_VERSION_MAJOR);
+ if (version_major != NULL && version_major[0] == '1') {
+ fprintf(stderr, "Error: GLEW version 2.0 and above is required.\n");
+ abort();
+ }
+ }
+#endif
+
+ const int profile_mask =
+#if defined(WITH_GL_PROFILE_CORE)
+ GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
#elif defined(WITH_GL_PROFILE_COMPAT)
- GHOST_Context *context = new GHOST_ContextGLX(
- m_wantStereoVisual,
- m_wantNumOfAASamples,
- m_window,
- m_display,
- m_visualInfo,
- (GLXFBConfig)m_fbconfig,
- 0, // profile bit
- 0, 0,
- GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
- GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
+ GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
#else
-# error
+# error // must specify either core or compat at build time
#endif
-#else
+ GHOST_Context *context;
+
+ for (int minor = 5; minor >= 0; --minor) {
+ context = new GHOST_ContextGLX(
+ m_wantStereoVisual,
+ m_wantNumOfAASamples,
+ m_window,
+ m_display,
+ m_visualInfo,
+ (GLXFBConfig)m_fbconfig,
+ profile_mask,
+ 4, minor,
+ GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
+ GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
+
+ if (context->initializeDrawingContext())
+ return context;
+ else
+ delete context;
+ }
-#if defined(WITH_GL_PROFILE_CORE)
- GHOST_Context *context = new GHOST_ContextEGL(
- m_wantStereoVisual,
- m_wantNumOfAASamples,
- m_window,
- m_display,
- EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
- 3, 2,
- GHOST_OPENGL_EGL_CONTEXT_FLAGS,
- GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
- EGL_OPENGL_API);
-#elif defined(WITH_GL_PROFILE_ES20)
- GHOST_Context *context = new GHOST_ContextEGL(
+ context = new GHOST_ContextGLX(
m_wantStereoVisual,
m_wantNumOfAASamples,
m_window,
m_display,
- 0, // profile bit
- 2, 0,
- GHOST_OPENGL_EGL_CONTEXT_FLAGS,
- GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
- EGL_OPENGL_ES_API);
-#elif defined(WITH_GL_PROFILE_COMPAT)
- GHOST_Context *context = new GHOST_ContextEGL(
- m_wantStereoVisual,
- m_wantNumOfAASamples,
- m_window,
- m_display,
- 0, // profile bit
- 0, 0,
- GHOST_OPENGL_EGL_CONTEXT_FLAGS,
- GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
- EGL_OPENGL_API);
-#else
-# error
-#endif
+ m_visualInfo,
+ (GLXFBConfig)m_fbconfig,
+ profile_mask,
+ 3, 3,
+ GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
+ GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
-#endif
if (context->initializeDrawingContext())
return context;
else
delete context;
+
}
return NULL;
diff --git a/intern/ghost/test/CMakeLists.txt b/intern/ghost/test/CMakeLists.txt
index fb9ef621ecf..ef6e8915871 100644
--- a/intern/ghost/test/CMakeLists.txt
+++ b/intern/ghost/test/CMakeLists.txt
@@ -203,7 +203,6 @@ target_link_libraries(gears_c
glewmx_lib
string_lib
${OPENGL_gl_LIBRARY}
- ${OPENGL_glu_LIBRARY}
${PLATFORM_LINKLIBS}
)
@@ -217,7 +216,6 @@ target_link_libraries(gears_cpp
glewmx_lib
string_lib
${OPENGL_gl_LIBRARY}
- ${OPENGL_glu_LIBRARY}
${PLATFORM_LINKLIBS}
)
@@ -248,7 +246,6 @@ target_link_libraries(multitest_c
guardedalloc_lib
wcwidth_lib
${OPENGL_gl_LIBRARY}
- ${OPENGL_glu_LIBRARY}
${FREETYPE_LIBRARY}
${ZLIB_LIBRARIES}
${PLATFORM_LINKLIBS}
diff --git a/intern/glew-mx/glew-mx.h b/intern/glew-mx/glew-mx.h
index ed17ea4a0e6..86f48a1068d 100644
--- a/intern/glew-mx/glew-mx.h
+++ b/intern/glew-mx/glew-mx.h
@@ -49,12 +49,6 @@
#ifndef __GLEW_MX_H__
#define __GLEW_MX_H__
-#ifdef WITH_GLEW_MX
-/* glew itself expects this */
-# define GLEW_MX 1
-# define glewGetContext() (&(_mx_context->glew_context))
-#endif
-
#include <GL/glew.h>
@@ -62,39 +56,16 @@
extern "C" {
#endif
-/* MXContext is used instead of GLEWContext directly so that
- extending what data is held by a context is easier.
- */
-typedef struct MXContext {
-#ifdef WITH_GLEW_MX
- GLEWContext glew_context;
-#endif
-
- int reserved; /* structs need at least one member */
-
-} MXContext;
-
-#ifdef WITH_GLEW_MX
-extern MXContext *_mx_context;
-#endif
-
-
#include "intern/symbol-binding.h"
/* If compiling only for OpenGL 3.2 Core Profile then we should make sure
* no legacy API entries or symbolic constants are used.
*/
-#if defined(WITH_GL_PROFILE_CORE) && !defined(WITH_GL_PROFILE_COMPAT) && !defined(WITH_GL_PROFILE_ES20)
+#if (!defined(WITH_LEGACY_OPENGL)) || defined(WITH_GL_PROFILE_CORE) && !defined(WITH_GL_PROFILE_COMPAT) && !defined(WITH_GL_PROFILE_ES20)
# include "intern/gl-deprecated.h"
#endif
-
-MXContext *mxCreateContext (void);
-MXContext *mxGetCurrentContext (void);
-void mxMakeCurrentContext(MXContext *ctx);
-void mxDestroyContext (MXContext *ctx);
-
GLenum glew_chk(GLenum error, const char *file, int line, const char *text);
#ifndef NDEBUG
diff --git a/intern/glew-mx/intern/gl-deprecated.h b/intern/glew-mx/intern/gl-deprecated.h
index 1a23642fbfc..669fb83a644 100644
--- a/intern/glew-mx/intern/gl-deprecated.h
+++ b/intern/glew-mx/intern/gl-deprecated.h
@@ -841,6 +841,7 @@
#undef GL_SOURCE2_RGB
#define GL_SOURCE2_RGB DO_NOT_USE_GL_SOURCE2_RGB
+#if 0 /* Those are deprecated but still valid */
// Old Token Names 3.0
#undef GL_CLIP_PLANE0
#define GL_CLIP_PLANE0 USE_GL_CLIP_DISTANCE0
@@ -864,9 +865,6 @@
// Old Token Names 3.2
#undef GL_VERTEX_PROGRAM_POINT_SIZE
#define GL_VERTEX_PROGRAM_POINT_SIZE USE_GL_PROGRAM_POINT_SIZE
-
-// Old Token Names 4.1
-#undef GL_CURRENT_PROGRAM
-#define GL_CURRENT_PROGRAM DO_NOT_USE_GL_CURRENT_PROGRAM
+#endif
#endif /* __GL_DEPRECATED_H__ */
diff --git a/intern/glew-mx/intern/glew-mx.c b/intern/glew-mx/intern/glew-mx.c
index 6fbb1a7a2e2..9db2d233085 100644
--- a/intern/glew-mx/intern/glew-mx.c
+++ b/intern/glew-mx/intern/glew-mx.c
@@ -84,61 +84,3 @@ GLenum glew_chk(GLenum error, const char *file, int line, const char *text)
return error;
}
-
-
-#ifdef WITH_GLEW_MX
-MXContext *_mx_context = NULL;
-#endif
-
-
-MXContext *mxCreateContext(void)
-{
-#ifdef WITH_GLEW_MX
- MXContext* new_ctx = calloc(1, sizeof(MXContext));
-
- if (new_ctx != NULL) {
- MXContext* cur_ctx = _mx_context;
- _mx_context = new_ctx;
- GLEW_CHK(glewInit());
- _mx_context = cur_ctx;
- }
-
- return new_ctx;
-#else
- GLEW_CHK(glewInit());
- return NULL;
-#endif
-}
-
-
-MXContext *mxGetCurrentContext(void)
-{
-#ifdef WITH_GLEW_MX
- return _mx_context;
-#else
- return NULL;
-#endif
-}
-
-
-void mxMakeCurrentContext(MXContext *ctx)
-{
-#ifdef WITH_GLEW_MX
- _mx_context = ctx;
-#else
- (void)ctx;
-#endif
-}
-
-
-void mxDestroyContext(MXContext *ctx)
-{
-#ifdef WITH_GLEW_MX
- if (_mx_context == ctx)
- _mx_context = NULL;
-
- free(ctx);
-#else
- (void)ctx;
-#endif
-}
diff --git a/intern/itasc/FixedObject.hpp b/intern/itasc/FixedObject.hpp
index ad26e7cb2d6..02c1804073c 100644
--- a/intern/itasc/FixedObject.hpp
+++ b/intern/itasc/FixedObject.hpp
@@ -21,7 +21,7 @@ public:
int addFrame(const std::string& name, const Frame& frame);
- virtual void updateCoordinates(const Timestamp& timestamp) {};
+ virtual void updateCoordinates(struct EvaluationContext *eval_ctx, const Timestamp& timestamp) {};
virtual int addEndEffector(const std::string& name);
virtual bool finalize();
virtual const Frame& getPose(const unsigned int frameIndex);
diff --git a/intern/itasc/MovingFrame.cpp b/intern/itasc/MovingFrame.cpp
index 90ebe091eb5..b1815ddd0de 100644
--- a/intern/itasc/MovingFrame.cpp
+++ b/intern/itasc/MovingFrame.cpp
@@ -90,7 +90,7 @@ bool MovingFrame::setCallback(MovingFrameCallback _function, void* _param)
return true;
}
-void MovingFrame::updateCoordinates(const Timestamp& timestamp)
+void MovingFrame::updateCoordinates(struct EvaluationContext *eval_ctx, const Timestamp& timestamp)
{
// don't compute the velocity during substepping, it is assumed constant.
if (!timestamp.substep) {
@@ -98,7 +98,7 @@ void MovingFrame::updateCoordinates(const Timestamp& timestamp)
if (!timestamp.reiterate) {
cacheAvail = popInternalFrame(timestamp.cacheTimestamp);
if (m_function)
- (*m_function)(timestamp, m_internalPose, m_nextPose, m_param);
+ (*m_function)(eval_ctx, timestamp, m_internalPose, m_nextPose, m_param);
}
// only compute velocity if we have a previous pose
if (cacheAvail && timestamp.interpolate) {
diff --git a/intern/itasc/MovingFrame.hpp b/intern/itasc/MovingFrame.hpp
index d2a956d7312..89519832840 100644
--- a/intern/itasc/MovingFrame.hpp
+++ b/intern/itasc/MovingFrame.hpp
@@ -11,10 +11,11 @@
#include "UncontrolledObject.hpp"
#include <vector>
+struct EvaluationContext;
namespace iTaSC{
-typedef bool (*MovingFrameCallback)(const Timestamp& timestamp, const Frame& _current, Frame& _next, void *param);
+typedef bool (*MovingFrameCallback)(struct EvaluationContext *eval_ctx, const Timestamp& timestamp, const Frame& _current, Frame& _next, void *param);
class MovingFrame: public UncontrolledObject {
public:
@@ -24,7 +25,7 @@ public:
bool setFrame(const Frame& frame);
bool setCallback(MovingFrameCallback _function, void* _param);
- virtual void updateCoordinates(const Timestamp& timestamp);
+ virtual void updateCoordinates(struct EvaluationContext *eval_ctx, const Timestamp& timestamp);
virtual void updateKinematics(const Timestamp& timestamp);
virtual void pushCache(const Timestamp& timestamp);
virtual void initCache(Cache *_cache);
diff --git a/intern/itasc/Scene.cpp b/intern/itasc/Scene.cpp
index 5768a994970..fd8b006d19c 100644
--- a/intern/itasc/Scene.cpp
+++ b/intern/itasc/Scene.cpp
@@ -257,7 +257,7 @@ bool Scene::getConstraintPose(ConstraintSet* constraint, void *_param, KDL::Fram
return true;
}
-bool Scene::update(double timestamp, double timestep, unsigned int numsubstep, bool reiterate, bool cache, bool interpolate)
+bool Scene::update(struct EvaluationContext *eval_ctx, double timestamp, double timestep, unsigned int numsubstep, bool reiterate, bool cache, bool interpolate)
{
// we must have valid timestep and timestamp
if (timestamp < KDL::epsilon || timestep < 0.0)
@@ -316,7 +316,7 @@ bool Scene::update(double timestamp, double timestep, unsigned int numsubstep, b
}
}
if (os->object->getType()==Object::UnControlled && ((UncontrolledObject*)os->object)->getNrOfCoordinates() != 0) {
- ((UncontrolledObject*)(os->object))->updateCoordinates(ts);
+ ((UncontrolledObject*)(os->object))->updateCoordinates(eval_ctx, ts);
if (!ts.substep) {
// velocity of uncontrolled object remains constant during substepping
project(m_xdot,os->coordinaterange) = ((UncontrolledObject*)(os->object))->getXudot();
diff --git a/intern/itasc/Scene.hpp b/intern/itasc/Scene.hpp
index 5ed031b543e..0039be07584 100644
--- a/intern/itasc/Scene.hpp
+++ b/intern/itasc/Scene.hpp
@@ -39,7 +39,7 @@ public:
bool addSolver(Solver* _solver);
bool addCache(Cache* _cache);
bool initialize();
- bool update(double timestamp, double timestep, unsigned int numsubstep=1, bool reiterate=false, bool cache=true, bool interpolate=true);
+ bool update(struct EvaluationContext *eval_ctx, double timestamp, double timestep, unsigned int numsubstep=1, bool reiterate=false, bool cache=true, bool interpolate=true);
bool setParam(SceneParam paramId, double value);
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
diff --git a/intern/itasc/UncontrolledObject.hpp b/intern/itasc/UncontrolledObject.hpp
index 81445538fa6..889bc742c6d 100644
--- a/intern/itasc/UncontrolledObject.hpp
+++ b/intern/itasc/UncontrolledObject.hpp
@@ -11,6 +11,9 @@
#include "eigen_types.hpp"
#include "Object.hpp"
+
+struct EvaluationContext;
+
namespace iTaSC{
class UncontrolledObject: public Object {
@@ -26,7 +29,7 @@ public:
virtual void initialize(unsigned int _nu, unsigned int _nf);
virtual const e_matrix& getJu(unsigned int frameIndex) const;
virtual const e_vector& getXudot() const {return m_xudot;}
- virtual void updateCoordinates(const Timestamp& timestamp)=0;
+ virtual void updateCoordinates(struct EvaluationContext *eval_ctx, const Timestamp& timestamp)=0;
virtual const unsigned int getNrOfCoordinates(){return m_nu;};
virtual const unsigned int getNrOfFrames(){return m_nf;};
diff --git a/intern/itasc/WorldObject.hpp b/intern/itasc/WorldObject.hpp
index 99756dcd684..b992445ab10 100644
--- a/intern/itasc/WorldObject.hpp
+++ b/intern/itasc/WorldObject.hpp
@@ -16,7 +16,7 @@ public:
WorldObject();
virtual ~WorldObject();
- virtual void updateCoordinates(const Timestamp& timestamp) {};
+ virtual void updateCoordinates(struct EvaluationContext *eval_ctx, const Timestamp& timestamp) {};
virtual void updateKinematics(const Timestamp& timestamp) {};
virtual void pushCache(const Timestamp& timestamp) {};
virtual void initCache(Cache *_cache) {};
diff --git a/intern/opencolorio/CMakeLists.txt b/intern/opencolorio/CMakeLists.txt
index 75e228933aa..2611477252a 100644
--- a/intern/opencolorio/CMakeLists.txt
+++ b/intern/opencolorio/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
.
../glew-mx
../guardedalloc
+ ../gawain
../../source/blender/blenlib
)
@@ -66,6 +67,7 @@ if(WITH_OPENCOLORIO)
endif()
data_to_c_simple(gpu_shader_display_transform.glsl SRC)
+ data_to_c_simple(gpu_shader_display_transform_vertex.glsl SRC)
endif()
diff --git a/intern/opencolorio/gpu_shader_display_transform.glsl b/intern/opencolorio/gpu_shader_display_transform.glsl
index 853bf575582..372d41dfecb 100644
--- a/intern/opencolorio/gpu_shader_display_transform.glsl
+++ b/intern/opencolorio/gpu_shader_display_transform.glsl
@@ -10,6 +10,10 @@ uniform float image_texture_width;
uniform float image_texture_height;
#endif
+in vec2 texCoord_interp;
+out vec4 fragColor;
+#define texture2D texture
+
#ifdef USE_CURVE_MAPPING
/* Curve mapping parameters
*
@@ -143,7 +147,7 @@ vec4 apply_dither(vec2 st, vec4 col)
void main()
{
- vec4 col = texture2D(image_texture, gl_TexCoord[0].st);
+ vec4 col = texture2D(image_texture, texCoord_interp.st);
#ifdef USE_CURVE_MAPPING
col = curvemapping_evaluate_premulRGBF(col);
#endif
@@ -165,8 +169,8 @@ void main()
vec4 result = OCIODisplay(col, lut3d_texture);
#ifdef USE_DITHER
- result = apply_dither(gl_TexCoord[0].st, result);
+ result = apply_dither(texCoord_interp.st, result);
#endif
- gl_FragColor = result;
+ fragColor = result;
}
diff --git a/intern/opencolorio/gpu_shader_display_transform_vertex.glsl b/intern/opencolorio/gpu_shader_display_transform_vertex.glsl
new file mode 100644
index 00000000000..054f7f3ec91
--- /dev/null
+++ b/intern/opencolorio/gpu_shader_display_transform_vertex.glsl
@@ -0,0 +1,12 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec2 texCoord;
+in vec2 pos;
+out vec2 texCoord_interp;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos.xy, 0.0f, 1.0f);
+ texCoord_interp = texCoord;
+}
diff --git a/intern/opencolorio/ocio_impl_glsl.cc b/intern/opencolorio/ocio_impl_glsl.cc
index bf91ea143da..b89221c36da 100644
--- a/intern/opencolorio/ocio_impl_glsl.cc
+++ b/intern/opencolorio/ocio_impl_glsl.cc
@@ -48,6 +48,9 @@
# pragma warning(pop)
#endif
+extern "C" {
+#include "gawain/immediate.h"
+}
using namespace OCIO_NAMESPACE;
@@ -58,6 +61,7 @@ using namespace OCIO_NAMESPACE;
static const int LUT3D_EDGE_SIZE = 64;
extern "C" char datatoc_gpu_shader_display_transform_glsl[];
+extern "C" char datatoc_gpu_shader_display_transform_vertex_glsl[];
/* **** OpenGL drawing routines using GLSL for color space transform ***** */
@@ -89,7 +93,9 @@ typedef struct OCIO_GLSLDrawState {
/* GLSL stuff */
GLuint ocio_shader;
+ GLuint vert_shader;
GLuint program;
+ Gwn_ShaderInterface *shader_interface;
/* Previous OpenGL state. */
GLint last_texture, last_texture_unit;
@@ -116,14 +122,15 @@ static GLuint compileShaderText(GLenum shaderType, const char *text)
return shader;
}
-static GLuint linkShaders(GLuint ocio_shader)
+static GLuint linkShaders(GLuint ocio_shader, GLuint vert_shader)
{
- if (!ocio_shader)
+ if (!ocio_shader || !vert_shader)
return 0;
GLuint program = glCreateProgram();
glAttachShader(program, ocio_shader);
+ glAttachShader(program, vert_shader);
glLinkProgram(program);
@@ -339,6 +346,25 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc
glDeleteShader(state->ocio_shader);
}
+ if (state->vert_shader) {
+ glDeleteShader(state->vert_shader);
+ }
+
+ /* Vertex shader */
+ std::ostringstream osv;
+
+ if (supportGLSL13()) {
+ osv << "#version 130\n";
+ }
+ else {
+ osv << "#version 120\n";
+ }
+
+ osv << datatoc_gpu_shader_display_transform_vertex_glsl;
+
+ state->vert_shader = compileShaderText(GL_VERTEX_SHADER, osv.str().c_str());
+
+ /* Fragment shader */
std::ostringstream os;
if (supportGLSL13()) {
@@ -366,8 +392,12 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc
state->ocio_shader = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
- if (state->ocio_shader) {
- state->program = linkShaders(state->ocio_shader);
+ if (state->ocio_shader && state->vert_shader) {
+ state->program = linkShaders(state->ocio_shader, state->vert_shader);
+ }
+
+ if (state->program) {
+ state->shader_interface = GWN_shaderinterface_create(state->program);
}
state->curve_mapping_used = use_curve_mapping;
@@ -386,10 +416,21 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc
glActiveTexture(GL_TEXTURE0);
- glUseProgram(state->program);
-
- glUniform1i(glGetUniformLocation(state->program, "image_texture"), 0);
- glUniform1i(glGetUniformLocation(state->program, "lut3d_texture"), 1);
+ /* IMM needs vertex format even if we don't draw with it.
+ *
+ * NOTE: The only reason why it's here is because of Cycles viewport.
+ * All other areas are managing their own vertex formats.
+ * Doing it here is probably harmless, but kind of stupid.
+ *
+ * TODO(sergey): Look into some nicer solution.
+ */
+ Gwn_VertFormat *format = immVertexFormat();
+ GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindProgram(state->program, state->shader_interface);
+
+ immUniform1i("image_texture", 0);
+ immUniform1i("lut3d_texture", 1);
if (state->texture_size_used) {
/* we use textureSize() if possible for best performance, if not
@@ -399,30 +440,30 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
- glUniform1f(glGetUniformLocation(state->program, "image_texture_width"), (float)width);
- glUniform1f(glGetUniformLocation(state->program, "image_texture_height"), (float)height);
+ immUniform1f("image_texture_width", (float)width);
+ immUniform1f("image_texture_height", (float)height);
}
if (use_dither) {
- glUniform1f(glGetUniformLocation(state->program, "dither"), dither);
+ immUniform1f("dither", dither);
}
if (use_curve_mapping) {
- glUniform1i(glGetUniformLocation(state->program, "curve_mapping_texture"), 2);
- glUniform1i(glGetUniformLocation(state->program, "curve_mapping_lut_size"), curve_mapping_settings->lut_size);
- glUniform4iv(glGetUniformLocation(state->program, "use_curve_mapping_extend_extrapolate"), 1, curve_mapping_settings->use_extend_extrapolate);
- glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_mintable"), 1, curve_mapping_settings->mintable);
- glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_range"), 1, curve_mapping_settings->range);
- glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_ext_in_x"), 1, curve_mapping_settings->ext_in_x);
- glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_ext_in_y"), 1, curve_mapping_settings->ext_in_y);
- glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_ext_out_x"), 1, curve_mapping_settings->ext_out_x);
- glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_ext_out_y"), 1, curve_mapping_settings->ext_out_y);
- glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_first_x"), 1, curve_mapping_settings->first_x);
- glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_first_y"), 1, curve_mapping_settings->first_y);
- glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_last_x"), 1, curve_mapping_settings->last_x);
- glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_last_y"), 1, curve_mapping_settings->last_y);
- glUniform3fv(glGetUniformLocation(state->program, "curve_mapping_black"), 1, curve_mapping_settings->black);
- glUniform3fv(glGetUniformLocation(state->program, "curve_mapping_bwmul"), 1, curve_mapping_settings->bwmul);
+ immUniform1i("curve_mapping_texture", 2);
+ immUniform1i("curve_mapping_lut_size", curve_mapping_settings->lut_size);
+ immUniform4iv("use_curve_mapping_extend_extrapolate", curve_mapping_settings->use_extend_extrapolate);
+ immUniform4fv("curve_mapping_mintable", curve_mapping_settings->mintable);
+ immUniform4fv("curve_mapping_range", curve_mapping_settings->range);
+ immUniform4fv("curve_mapping_ext_in_x", curve_mapping_settings->ext_in_x);
+ immUniform4fv("curve_mapping_ext_in_y", curve_mapping_settings->ext_in_y);
+ immUniform4fv("curve_mapping_ext_out_x", curve_mapping_settings->ext_out_x);
+ immUniform4fv("curve_mapping_ext_out_y", curve_mapping_settings->ext_out_y);
+ immUniform4fv("curve_mapping_first_x", curve_mapping_settings->first_x);
+ immUniform4fv("curve_mapping_first_y", curve_mapping_settings->first_y);
+ immUniform4fv("curve_mapping_last_x", curve_mapping_settings->last_x);
+ immUniform4fv("curve_mapping_last_y", curve_mapping_settings->last_y);
+ immUniform3fv("curve_mapping_black", curve_mapping_settings->black);
+ immUniform3fv("curve_mapping_bwmul", curve_mapping_settings->bwmul);
}
return true;
@@ -439,7 +480,7 @@ void OCIOImpl::finishGLSLDraw(OCIO_GLSLDrawState *state)
{
glActiveTexture(state->last_texture_unit);
glBindTexture(GL_TEXTURE_2D, state->last_texture);
- glUseProgram(0);
+ immUnbindProgram();
}
void OCIOImpl::freeGLState(struct OCIO_GLSLDrawState *state)
@@ -455,6 +496,9 @@ void OCIOImpl::freeGLState(struct OCIO_GLSLDrawState *state)
if (state->program)
glDeleteProgram(state->program);
+ if (state->shader_interface)
+ GWN_shaderinterface_discard(state->shader_interface);
+
if (state->ocio_shader)
glDeleteShader(state->ocio_shader);
diff --git a/intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl b/intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl
index 3a83d44a8be..b16a5cca733 100644
--- a/intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl
+++ b/intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl
@@ -29,22 +29,11 @@ struct VertexData {
vec2 uv;
};
-#if __VERSION__ >= 150
layout(lines_adjacency) in;
- #ifdef WIREFRAME
+#ifdef WIREFRAME
layout(line_strip, max_vertices = 8) out;
- #else
-layout(triangle_strip, max_vertices = 4) out;
- #endif
#else
- #extension GL_EXT_geometry_shader4: require
- /* application provides input/output layout info */
-#endif
-
-#if __VERSION__ < 140
- #extension GL_ARB_uniform_buffer_object: require
- #extension GL_ARB_texture_buffer_object: enable
- #extension GL_EXT_texture_buffer_object: enable
+layout(triangle_strip, max_vertices = 4) out;
#endif
uniform mat4 modelViewMatrix;
diff --git a/intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl b/intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl
index 6d3c06f59c9..6fcf5ad20cd 100644
--- a/intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl
+++ b/intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl
@@ -43,11 +43,4 @@ void main()
{
outpt.v.position = modelViewMatrix * position;
outpt.v.normal = normalize(normalMatrix * normal);
-
-#if __VERSION__ < 140
- /* Some compilers expects gl_Position to be written.
- * It's not needed once we explicitly switch to GLSL 1.40 or above.
- */
- gl_Position = outpt.v.position;
-#endif
}
diff --git a/intern/opensubdiv/opensubdiv_capi.cc b/intern/opensubdiv/opensubdiv_capi.cc
index 0a55a432cc6..bb865bc0e0f 100644
--- a/intern/opensubdiv/opensubdiv_capi.cc
+++ b/intern/opensubdiv/opensubdiv_capi.cc
@@ -412,19 +412,6 @@ const struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_getGLMeshTopologyRefine
return gl_mesh->topology_refiner;
}
-int openSubdiv_supportGPUDisplay(void)
-{
- // TODO: simplify extension check once Blender adopts GL 3.2
- return openSubdiv_gpu_legacy_support() &&
- (GLEW_VERSION_3_2 ||
- (GLEW_VERSION_3_1 && GLEW_EXT_geometry_shader4) ||
- (GLEW_VERSION_3_0 &&
- GLEW_EXT_geometry_shader4 &&
- GLEW_ARB_uniform_buffer_object &&
- (GLEW_ARB_texture_buffer_object || GLEW_EXT_texture_buffer_object)));
- /* also ARB_explicit_attrib_location? */
-}
-
int openSubdiv_getVersionHex(void)
{
#if defined(OPENSUBDIV_VERSION_NUMBER)
diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h
index 281bd3f010d..2c3fcee7dbb 100644
--- a/intern/opensubdiv/opensubdiv_capi.h
+++ b/intern/opensubdiv/opensubdiv_capi.h
@@ -146,11 +146,9 @@ void openSubdiv_osdGLAllocFVar(struct OpenSubdiv_TopologyRefinerDescr *topology_
void openSubdiv_osdGLDestroyFVar(OpenSubdiv_GLMesh *gl_mesh);
/* ** Utility functions ** */
-int openSubdiv_supportGPUDisplay(void);
int openSubdiv_getAvailableEvaluators(void);
-void openSubdiv_init(bool gpu_legacy_support);
+void openSubdiv_init(void);
void openSubdiv_cleanup(void);
-bool openSubdiv_gpu_legacy_support(void);
int openSubdiv_getVersionHex(void);
diff --git a/intern/opensubdiv/opensubdiv_gpu_capi.cc b/intern/opensubdiv/opensubdiv_gpu_capi.cc
index c36eaae1c6e..811cd18745e 100644
--- a/intern/opensubdiv/opensubdiv_gpu_capi.cc
+++ b/intern/opensubdiv/opensubdiv_gpu_capi.cc
@@ -275,24 +275,6 @@ GLuint linkProgram(const char *version, const char *define)
glBindAttribLocation(program, 0, "position");
glBindAttribLocation(program, 1, "normal");
-
- if (!GLEW_VERSION_3_2) {
- /* provide input/output layout info */
- glProgramParameteriEXT(program,
- GL_GEOMETRY_INPUT_TYPE_EXT,
- GL_LINES_ADJACENCY_EXT);
-
- bool wireframe = strstr(define, "WIREFRAME") != NULL;
-
- glProgramParameteriEXT(program,
- GL_GEOMETRY_OUTPUT_TYPE_EXT,
- wireframe ? GL_LINE_STRIP : GL_TRIANGLE_STRIP);
-
- glProgramParameteriEXT(program,
- GL_GEOMETRY_VERTICES_OUT_EXT,
- 8);
- }
-
glLinkProgram(program);
glDeleteShader(vertexShader);
@@ -314,17 +296,26 @@ GLuint linkProgram(const char *version, const char *define)
glGetUniformBlockIndex(program, "Lighting"),
0);
- glProgramUniform1i(program,
- glGetUniformLocation(program, "texture_buffer"),
- 0); /* GL_TEXTURE0 */
+ if (GLEW_VERSION_4_1) {
+ glProgramUniform1i(program,
+ glGetUniformLocation(program, "texture_buffer"),
+ 0); /* GL_TEXTURE0 */
- glProgramUniform1i(program,
- glGetUniformLocation(program, "FVarDataOffsetBuffer"),
- 30); /* GL_TEXTURE30 */
+ glProgramUniform1i(program,
+ glGetUniformLocation(program, "FVarDataOffsetBuffer"),
+ 30); /* GL_TEXTURE30 */
- glProgramUniform1i(program,
- glGetUniformLocation(program, "FVarDataBuffer"),
- 31); /* GL_TEXTURE31 */
+ glProgramUniform1i(program,
+ glGetUniformLocation(program, "FVarDataBuffer"),
+ 31); /* GL_TEXTURE31 */
+ }
+ else {
+ glUseProgram(program);
+ glUniform1i(glGetUniformLocation(program, "texture_buffer"), 0); /* GL_TEXTURE0 */
+ glUniform1i(glGetUniformLocation(program, "FVarDataOffsetBuffer"), 30); /* GL_TEXTURE30 */
+ glUniform1i(glGetUniformLocation(program, "FVarDataBuffer"), 31); /* GL_TEXTURE31 */
+ glUseProgram(0);
+ }
return program;
}
@@ -353,10 +344,8 @@ void bindProgram(OpenSubdiv_GLMesh *gl_mesh, int program)
glBindBufferBase(GL_UNIFORM_BUFFER, 0, g_lighting_ub);
/* Color */
- GLboolean use_lighting;
- glGetBooleanv(GL_LIGHTING, &use_lighting);
-
- if (use_lighting) {
+ {
+ /* TODO: stop using glGetMaterial */
float color[4];
glGetMaterialfv(GL_FRONT, GL_DIFFUSE, color);
glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color);
@@ -367,11 +356,6 @@ void bindProgram(OpenSubdiv_GLMesh *gl_mesh, int program)
glGetMaterialfv(GL_FRONT, GL_SHININESS, color);
glUniform1f(glGetUniformLocation(program, "shininess"), color[0]);
}
- else {
- float color[4];
- glGetFloatv(GL_CURRENT_COLOR, color);
- glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color);
- }
/* Face-vertex data */
if (gl_mesh->fvar_data != NULL) {
@@ -409,11 +393,10 @@ bool openSubdiv_osdGLDisplayInit(void)
{
static bool need_init = true;
static bool init_success = false;
- if (need_init) {
- if (!openSubdiv_supportGPUDisplay()) {
- return false;
- }
+ if (need_init) {
+ /* TODO: update OSD drawing to OpenGL 3.3 core, then remove following line */
+ return false;
const char *version = "";
if (GLEW_VERSION_3_2) {
@@ -538,6 +521,7 @@ void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl,
g_lighting_data.num_enabled++;
}
+ /* TODO: stop using glGetLight */
glGetLightfv(GL_LIGHT0 + i,
GL_POSITION,
g_lighting_data.lights[i].position);
@@ -635,31 +619,24 @@ static GLuint prepare_patchDraw(OpenSubdiv_GLMesh *gl_mesh,
GLboolean use_texture_2d, use_lighting;
glGetIntegerv(GL_SHADE_MODEL, &model);
glGetBooleanv(GL_TEXTURE_2D, &use_texture_2d);
- glGetBooleanv(GL_LIGHTING, &use_lighting);
+
if (model == GL_FLAT) {
if (use_texture_2d) {
- program = use_lighting
- ? g_flat_fill_texture2d_program
- : g_flat_fill_texture2d_shadeless_program;
+ program = g_flat_fill_texture2d_program;
}
else {
- program = use_lighting
- ? g_flat_fill_solid_program
- : g_flat_fill_solid_shadeless_program;
+ program = g_flat_fill_solid_program;
}
}
else {
if (use_texture_2d) {
- program = use_lighting
- ? g_smooth_fill_texture2d_program
- : g_smooth_fill_texture2d_shadeless_program;
+ program = g_smooth_fill_texture2d_program;
}
else {
- program = use_lighting
- ? g_smooth_fill_solid_program
- : g_smooth_fill_solid_shadeless_program;
+ program = g_smooth_fill_solid_program;
}
}
+
}
else {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
diff --git a/intern/opensubdiv/opensubdiv_utils_capi.cc b/intern/opensubdiv/opensubdiv_utils_capi.cc
index ae5592367dd..72e3751e6b3 100644
--- a/intern/opensubdiv/opensubdiv_utils_capi.cc
+++ b/intern/opensubdiv/opensubdiv_utils_capi.cc
@@ -41,14 +41,8 @@
# include "opensubdiv_device_context_cuda.h"
#endif /* OPENSUBDIV_HAS_CUDA */
-static bool gpu_legacy_support_global = false;
-
int openSubdiv_getAvailableEvaluators(void)
{
- if (!openSubdiv_supportGPUDisplay()) {
- return 0;
- }
-
int flags = OPENSUBDIV_EVALUATOR_CPU;
#ifdef OPENSUBDIV_HAS_OPENMP
@@ -82,19 +76,13 @@ int openSubdiv_getAvailableEvaluators(void)
return flags;
}
-void openSubdiv_init(bool gpu_legacy_support)
+void openSubdiv_init(void)
{
/* Ensure all OpenGL strings are cached. */
(void)openSubdiv_getAvailableEvaluators();
- gpu_legacy_support_global = gpu_legacy_support;
}
void openSubdiv_cleanup(void)
{
openSubdiv_osdGLDisplayDeinit();
}
-
-bool openSubdiv_gpu_legacy_support(void)
-{
- return gpu_legacy_support_global;
-}