1
1

Compare commits

...

92 Commits

Author SHA1 Message Date
bcf1626934 cleanup: GPUBufferCopyFunc defined twice 2015-05-14 13:17:12 -04:00
8e08b34061 clean up GPUx vertex buffer API (part 1)
Removed unprimed version of GPUx_vertex_buffer_use function. The new
pattern is create, fill, prime, use {draw} done_using, use {draw}
done_using ...

Renamed GPUx_vertex_buffer_use_primed to GPUx_vertex_buffer_use since
there's only one version now.

Also removed the _primed suffix from GPUx_element_list_use.

TODO: make a wiki page about how to use this API
2015-05-14 02:57:40 -04:00
d58765ccb3 fix mismatched memory free
This string is copied with strdup during GPUx_specify_attrib, needs a
plain free.
2015-05-14 00:38:10 -04:00
25e492edaa new function: bind all attrib locations
Was binding these by hand in wireframe shader tests, but retyping the
name strings is a potential source of errors. Call this function instead
after creating VertexBuffer but before linking the GLSL program.
2015-05-13 23:57:03 -04:00
eb42cbf273 Revert "Add missing stubs for buffer generation."
This reverts commit 4040f0af00.
2015-05-12 17:16:50 -04:00
247a1659fa Merge branch 'master' into GPU_data_request 2015-05-11 11:09:04 +02:00
4040f0af00 Add missing stubs for buffer generation. 2015-05-11 11:08:40 +02:00
95ca1ed75d Compilation fixes for C90 - still getting link errors related to buffer
generation routines.
2015-05-11 11:04:19 +02:00
b733d44f04 WIP: fancy wireframe display
Exploring some possibilities with wireframe rendering beyond solid
color.

New effect: color edges based on angle between the faces joined. Loose
edges, perimeter edges, and edges joining 3+ faces are colored
differently.

Some of this code will move to Workflow Shaders. Other parts will move
to DerivedMesh data requests — AdjacentFaces (struct) and/or angle made
by adjacent faces (float).

The (incomplete) shader version uses VertexBuffer’s generic attribute
API, which we want to switch everything to eventually. There is a GLSL
vertex shader *not* included in this commit because I don’t know where
to put it…

The CPU version is temporary — it’s equivalent to the shader setup +
matching GLSL shader.

This particular effect is view independent, so can be done CPU-side
once and drawn many times. Other effects I’m working on are view
dependent, so really need the setup + shader split.
2015-04-28 19:45:58 -04:00
09076e4f99 check extensions before use in GPUx
Using VAOs and integer vertex attributes.

VBO support is *not* checked because it’s guaranteed to be there in a
GL 2.1 context.

VAOs are not part of GL 2.1, but enjoy nearly universal support.

gpu_shader4 is widely supported on recent hardware, not always on older
HW.
2015-04-27 14:55:26 -04:00
9e8f939769 add runtime check for gpu_shader4 support
This extension includes a number of GLSL enhancements:
- full integer support
- interpolation qualifiers (flat, smooth, noperspective)
- gl_VertexID, gl_PrimitiveID
- custom fragment shader outputs, for MRT
2015-04-27 14:40:46 -04:00
b9ac83ce9d single alloc per VertexBuffer, down from 2
Using flexible array member from C99.

Tested on LLVM/clang, also supported in GCC and MSVC according to docs:

https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
https://msdn.microsoft.com/en-us/library/b6fae073.aspx
2015-04-23 05:36:59 -04:00
1178265b0d minor cleanup
Mostly moving stuff to where it belongs.

UNUSED_VARS macro explains intent better than (void)var, so use it.

Considered replacing calloc with malloc for ElementList.indices, but
it’s safer to zero this in case not all primitives are set. So calloc
it stays!
2015-04-23 05:00:22 -04:00
4d972a5606 keep vertex data in main mem or VRAM (not both)
If we’re using VBOs, free our own copy once GL has the data.

Data always lives in main memory while being constructed, so that we
don’t need to call any OpenGL functions until it’s time to draw.
2015-04-23 03:06:30 -04:00
6f51182755 minor cleanup 2015-04-23 01:29:54 -04:00
316b953e34 reset shading to SMOOTH or FLAT
missed this as part of GPUx interpolation commit
2015-04-23 00:38:26 -04:00
7cb24b52d7 cleanup my own recent stuff 2015-04-22 03:30:00 -04:00
1653bbc778 reduce VRAM usage for flat normals
Reduce number of GL verts from (3 * tess_tri_ct) to (1 * loop_ct).
Attribute data formats unchanged.

stock Suzanne mesh
507 verts, 1005 edges, 500 polys, 500 faces, 1968 loops

mode = NORMAL_DRAW_FLAT

(3 * tri_ct) verts, vec3s normals (+padding)
GPUx batch size: 63886 bytes

(3 * tri_ct) verts, vec3s normals (no padding)
GPUx batch size: 58080 bytes

loop_ct verts, vec3s normals (+padding)
GPUx batch size: 45166 bytes

loop_ct verts, vec3s normals (no padding)
GPUx batch size: 41232 bytes
2015-04-22 02:59:55 -04:00
27fe1353ad reduce VRAM usage for loop normals
Use GL_SHORT instead of GL_FLOAT for normal attribute. Savings scale
proportional to loop count.

stock Suzanne mesh
507 verts, 1005 edges, 500 polys, 500 faces, 1968 loops

mode = NORMAL_DRAW_LOOP

vec3f normals
GPUx batch size: 53040 bytes

vec3s normals (+padding)
GPUx batch size: 45166 bytes

vec3s normals (no padding)
GPUx batch size: 41232 bytes
2015-04-22 02:13:42 -04:00
6ccc770a95 determine normal draw mode better
based on auto smooth, how many faces are flat vs. smooth, and viewport
overrides.
2015-04-22 01:23:36 -04:00
562d6ee7c4 fix compiler warnings (gcc 4.9) 2015-04-21 22:01:44 -04:00
249a1e7f18 Mesh drawing: loop normals
Looks good, matches existing viewport.

Still room for size optimization here and with flat shading.
2015-04-21 17:17:20 -04:00
8e069c4f8d fix compile on MSVC
BLI_threads uses bool, so depends on include order. Proper fix would be
to #include <stdbool.h> in BLI_threads.h but I don't want to modify in
this branch.
2015-04-21 03:15:51 -04:00
59593af2a7 disable logging of orphaned GL buffer IDs 2015-04-21 03:02:30 -04:00
f0caa0bbad Merge remote-tracking branch 'origin/GPU_data_request' into GPU_data_request
Conflicts (resolved):
	source/blender/gpu/intern/gpux_draw.c
	source/blender/gpu/intern/gpux_element.c
	source/blender/gpu/intern/gpux_vbo.c
2015-04-21 02:27:52 -04:00
0ea4747752 Mesh drawing: variety of surface normal treatments
Can be NONE, SMOOTH, FLAT or LOOP.
LOOP is unfinished at the moment.
NONE might be pulled into its own drawing override mode.

Note: this commit includes some debug/tracing that is still useful to
me but will be removed in the future.
2015-04-21 01:41:26 -04:00
1cc677a037 const-ify BKE_mesh_calc_poly_normal
Some of my new mesh drawing code needs to call this with const data.

TODO: swing the “const hammer” at more BKE_mesh functions
2015-04-21 00:35:52 -04:00
1543c3f706 very minor cleanup 2015-04-21 00:31:29 -04:00
10f095463c manage GL buffer IDs in a thread-safe way
Old way was causing crash in GL when DerivedMesh discarded its
GPUxBatch from another thread.

New way deletes ID when safe to do so, otherwise “orphans” the ID to be
deleted later.
2015-04-21 00:30:30 -04:00
61978bbf32 add GPUxBatch size query
How much VRAM does our draw data use? Or process memory for client-side
data.

Note: right now data is stored in *both* places, but the code will be
smarter about storage in the future.
2015-04-19 03:06:52 -04:00
bcddec8a45 Use BLI_assert instead of assert 2015-04-17 17:31:45 +02:00
b138fbe4a1 Use our own allocation routines for GPUx module 2015-04-17 16:36:04 +02:00
805ddc7790 Merge branch 'master' into GPU_data_request
Conflicts:
	source/blender/makesdna/DNA_view3d_types.h
2015-04-17 11:37:34 +02:00
b91ebca68e add to GPUx state: interpolation (smooth shading)
and remove manual calls to glShadeModel.

TODO: interpolation qualifier per attrib (flat/smooth/noperspective)
instead of here.

This requires GLSL 1.3 (OpenGL 3.0) or EXT_gpu_shader4 so we can’t go
down that path yet.
2015-04-17 01:16:21 -04:00
4b88dbb06e remove short int -> float conversion for vertex normals
Performance experiment — thought this might be slowing down large
shaded meshes on Mac + nVidia but it was not. Index buffers in VRAM
fixed the perf issue :)

Keeping normals as GL_SHORT uses less memory. Would be 1/2 but
padding/alignment makes it 2/3. These stay GL_SHORT in VRAM also, and
are converted to floats when loaded by the vertex shader.
2015-04-16 23:23:46 -04:00
3541f234a2 fix compiler warnings (gcc 4.9) 2015-04-16 17:10:06 -04:00
6695dd5eea store index buffers in VRAM
With this change, smooth solid meshes draw faster in the new viewport
than old with VBOs.

Wireframe was already faster, now it's CRAZY fast.
2015-04-16 16:11:55 -04:00
33f85d0fe2 cache GPUx batches for performance++
WIP — developed on Mac, want to test on Linux & Windows so pushing
unfinished.

Everything needed for drawing is collected into a GPUxBatch. These are
generated per-object the first time drawn, then reused for subsequent
draws. Regenerated when DerivedMesh or draw mode changes.

TODO:
- actively reclaim memory (like gpu_buffers.c’s pool)
- store a list of batches per DM, for complex drawing
- find cause of low perf on high poly OB_SOLID rendering
2015-04-16 13:56:34 -04:00
26e5c28d39 init GL state tracking *after* clearing viewport
Clear function doesn’t use state tracking, sets GL directly.
2015-04-13 16:11:57 -04:00
86b9bcbfb4 workaround for VBOs on Mesa 2015-04-13 04:34:35 -04:00
d77ec2153b Fix crashes on undo when workflow has a nodetree.
Still getting memory leaks on exit, they likely occur because main is
owner of nodetree but we should give it to workflow instead.
2015-04-11 01:16:42 +02:00
404c9e1b7a Workflow shader fixes:
* ID type for GPUWorkflow shaders gets refined correctly
* GPUWorkflow correctly linked to spaceview3d when loading file
* Correct Icons in Node editor
* Creating a node tree works (but it's empty)
2015-04-10 23:34:13 +02:00
0b2abe145a WIP new node type for workflow shaders 2015-04-10 17:50:14 +02:00
418041628a Workflow shader data
Hook the struct to more places. Now there is a button
to choose a workflow instead of a draw type in the new viewport
(still needs to be somehow sorted according to object mode)
2015-04-10 16:38:42 +02:00
62ee03467a Add workflow shader ID to the system
Only struct definitions here. Workflow is also
set per 3d region. (We should be able to get a
workflow per region just like current textured,
solid etc modes can be set per 3D region)
2015-04-10 15:00:10 +02:00
dea27f08eb Add compositing and proper back drawing back to new viewport. 2015-04-10 14:26:12 +02:00
d3bd16b208 draw grid floor with GPUx API
Single draw call for the default case (grid floor with X and Y axes).

Z axis needs a second draw call because it uses 3D coordinates.
2015-04-09 22:24:02 -04:00
028adae2b5 add vec2f convenience function to GPUx 2015-04-09 22:13:40 -04:00
f2ef00f80e improve grid floor drawing function
Maintain visual hierarchy of the grid:
- emphasized lines draw atop normal lines
- axes draw atop all lines (same as before)

Draw axes only once, not twice.

Return early if nothing to draw.
2015-04-09 21:33:07 -04:00
cd454ab5b7 state tracking API - reorder function args
in order of importance.

Doing this early, before it’s used in more places.
2015-04-09 03:54:01 -04:00
e12432ac71 state tracking API - pass NULL to use defaults
reduces typing needed
2015-04-09 03:30:43 -04:00
165dab3551 new grid floor drawing function
changes:
- use vec2 instead of vec3 for grid
- single glBegin/End for axis lines
- draw axes regardless of grid-line count
- use depth buffer
2015-04-09 02:44:05 -04:00
699d7fd732 tweak GL state tracking
New defaults to match common 3D view usage:
- draw both sides (backface culling off)
- depth buffer test & write enabled

Also made default state more readable.
Fixed copy-paste error, GL_POLYGON_STIPPLE.

Mesh objects now draw fine in wireframe and (smooth) solid modes. Now
compatible with UI widgets drawn later!
2015-04-09 02:35:11 -04:00
12820473b2 add runtime check for VAO support 2015-04-07 19:13:30 -04:00
0aebd1b039 smooth lit meshes
WIP… still having some depth buffer issues
2015-04-07 04:56:18 -04:00
8599cfde8e draw derived mesh with GPUx API 2015-04-07 02:07:33 -04:00
3eaf30d216 draw base mesh with GPUx API
Vertex and Edge work great, Face not so much yet — totface = 0 so
nothing is drawn. Will work on derived mesh next.

draw_mesh_object_new_new is simplified to draw mesh geometry and
nothing else. Use draw_mesh_object or draw_mesh_object_new for full
functionality.
2015-04-06 16:04:16 -04:00
dc7a82e5e5 tweak GPUx draw to use actual max index
instead of max allowed index.

This is a looser restriction than before.
2015-04-06 15:43:59 -04:00
d664818c96 fix compilation when TRUST_NO_ONE is disabled 2015-04-04 03:53:40 -04:00
91cd1d98f6 More changes to defines, add GPUx prefix to public API 2015-04-03 12:32:45 +02:00
f40ffb79d4 More compilation fixes - add new files for cmake, make files conform to
old C (no declarations, use #ifdef instead or #if).
2015-04-03 12:13:28 +02:00
4d506c6303 Compile fixes for strict C - no declarations allowed in for loops and in
middle of blocks.
2015-04-03 11:41:23 +02:00
77aafef4b7 start using batched geometry API
Made “new new” version of drawcamera() to test out new drawing code.

Kept “old new” version for comparison.

Uses GL state tracking, partly disabled because it *almost* works —
need to find defaults that agree with UI drawing code.
2015-04-02 21:14:39 -04:00
995c613404 fixed issues in batched geometry API
- made default state available to all
- fixed vertex index tracking
- fixed attrib stride calculation
- fixed VBO binding
- fixed VAO attrib enables
2015-04-02 20:59:43 -04:00
9e7c8641e7 fix errors & warnings
toggling all #defines
2015-04-01 21:29:55 -04:00
c8d50ba9e6 fix VAOs on Mac legacy context
GLEW gives us glBindVertexArray and friends but sets them to NULL,
since Apple uses GL_APPLE_vertex_array_object instead of
GL_ARB_vertex_array_object. The ARB version evolved from the APPLE
version and they’re used in exactly the same way, so I aliased them to
keep our VAO code simple.
2015-04-01 20:37:17 -04:00
24dba1cbe9 tweak GL state tracking functions
Needed a way to force all currently tracked state to GL, for interop
with code that doesn’t use this API.
2015-03-31 14:42:07 -04:00
4ab3f9fb1f refactor vertex attrib handling
Found lots of commonality between generic and legacy attributes.

Also fixed an error found by flipping all the defines on & off.
2015-03-31 03:47:08 -04:00
20ce77c93c delete temp file
from merge conflict resolution, didn’t mean to commit
2015-03-31 03:30:24 -04:00
510af625bd remove unused attrib print routines 2015-03-31 01:32:25 -04:00
bc4b72eabd add support for non-generic vertex attribs
for easier integration into legacy GL usage.

Instead of specifying generic arrays with a name string, choose any or
all of these:

GL_VERTEX_ARRAY
GL_NORMAL_ARRAY
GL_COLOR_ARRAY
GL_TEXTURE_COORD_ARRAY

Generic attribs are still there for when we move to shader-based
drawing / a newer GL.
2015-03-31 01:25:43 -04:00
2398f8713a change function prefix to cdDM to match 2015-03-30 17:01:05 -04:00
84f4c305f9 Merge branch 'master' into GPU_data_request
Resolved conflict:
	source/blender/gpu/intern/gpu_buffers.c
2015-03-30 16:54:30 -04:00
2250834b40 use glDrawRangeElements for camera
glDrawElements has no way to say how much data from the vertex array is
needed, so use the Range variant instead.

glDrawArrays already has this range info.
2015-03-29 02:04:35 -04:00
d119166464 draw camera in 1 GL call (2 for active cam) 2015-03-29 01:51:13 -04:00
fcb2b87932 draw camera using vertex array 2015-03-29 01:26:00 -04:00
cfc05b0e99 put all OB_CAMERA verts in single array
also disable camera border hack (used for viewing THROUGH camera) to
focus on whole-camera drawing.
2015-03-29 01:03:58 -04:00
38ed5b82b3 remove unused test pattern
Helped for orientation before objects were drawn, no longer needed.
2015-03-29 00:22:44 -04:00
9965160c58 new draw path for Mesh & Camera objects
Used only when “new viewport” pref is checked, so we can switch back &
forth for comparison.

Camera because it’s simple — scoped some vars, removed an extra line
segment, touch back face cull state only when needed.

Mesh because it’s interesting — very little difference, just factored
out edit mesh drawing & touch back face cull state only when needed.

Also added (temporary) call graph tracing, to help me make sense of the
object drawing logic.

More to come for these object types, will run with these and add more
object types later. Not using our new APIs yet but that is the goal.
2015-03-28 04:33:47 -04:00
7bcb4fbf73 shell of a GLSL material node
This will hold a single GLSL function, which can be mixed & matched
with other nodes.

Goal: similar workflow to OSL shader node but for real-time rendering,
not Cycles.
2015-03-27 04:12:36 -04:00
6fc928599b cleanup: redundant include & defines
GLEW takes care of this.

VAOs are not part of OpenGL 2.1 but are very widely supported. Even so
we should check before using. Current code does not check.

Also minor style things I missed in the previous commit.
2015-03-21 04:23:29 -04:00
5b10412103 cleanup: code style
C-style comments, braces & pointer placement.
2015-03-21 02:06:54 -04:00
50a511b76e compile fixes for MSVC 2015-03-20 23:55:39 -04:00
49b2228c0e draw grid floor & objects in new viewport
Yanked verbatim from view3d_draw_objects, so there’s nothing “new”
about drawing method. But it does let us see objects positioned in
space which shows us transforms are working properly.
2015-03-20 18:34:13 -04:00
358732c463 OpenGL batched geometry API (experimental)
Clean slate design, with some overlap with existing Blender APIs. Using
GPUx_ prefix to avoid confusion with current GPU_ files.

- specify vertex attribs
- buffer in main memory & VRAM
- build element lists of points, lines, triangles
- draw these --^
- state tracking (fairly basic)
- lots of error & bounds checking!!! can turn this off

The idea is to handle things like VBOs, VAOs, other useful extensions
automatically so users of this API don't have to work hard to get it
right every time. This also lets us turn things on/off in one place for
debugging & perf measurements.

- - - -
Checking this code in now to give it a home & test on multiple systems.
It’s not being used yet and will probably evolve quite a bit as our
needs become clearer.
2015-03-20 18:16:56 -04:00
ded1d86b82 Just clear the buffers in new viewport 2015-02-23 11:18:17 +01:00
022d91bcf6 Flag for new viewport 2015-02-23 11:00:07 +01:00
49385d8b1b Also move new gpu object to derived mesh - we can probably do a few
abstractions here, but gpuObject creation is a bit derivedmesh type
specific (each DM has its own way to calculate vertices needed etc).
2015-02-18 15:35:08 +01:00
0703ba898e Move data copying function from gpu_buffers.c to cdderivedmesh.c (as it
should be, since it's specialized to this derivedmesh type)
2015-02-18 15:19:31 +01:00
9efc674800 Merge branch 'master' into GPU_data_request 2015-02-17 19:02:53 +01:00
d67d29035a Fix some ordering issues, remove leftover glBegin/glEnd 2015-02-09 14:23:58 +01:00
f07ca03185 Initial VBO code for GPU subsurf.
This commit adds a few generalizations to the VBO
code so that modifiers can create and populate their own GPU objects.

The VBO code originally supported CDDerivedMesh only. The design moves slightly
towards the viewport refactor where the rendering system requests data from the
modifiers.

In this commit only basic support for vertices and normals is provided and
some features from blender's VBO system, suchs as mapping to original faces,
unique element indices for vertices and loose vertex/edge support are missing.
Also, the quick navigation feature of the subsurf modifier won't be supported
for now.

What we do have is full support for solid shading with multiple materials,
flat/smooth shading and a big performance boost.
2015-02-09 14:19:03 +01:00
66 changed files with 4478 additions and 549 deletions

View File

@@ -182,8 +182,11 @@ def write_sysinfo(op):
output.write("\nImplementation Dependent OpenGL Limits:\n")
output.write(lilies)
limit = bgl.Buffer(bgl.GL_INT, 1)
limit_fl = bgl.Buffer(bgl.GL_FLOAT, 2)
bgl.glGetIntegerv(bgl.GL_MAX_TEXTURE_UNITS, limit)
output.write("Maximum Fixed Function Texture Units:\t%d\n" % limit[0])
bgl.glGetFloatv(bgl.GL_MAX_TEXTURE_UNITS, limit_fl)
output.write("Point Sprite Size Range:\t Max: %f Min: %f\n" % (limit_fl[0], limit_fl[1]))
output.write("\nGLSL:\n")
if version[0] > '1':

View File

@@ -105,6 +105,10 @@ class NODE_HT_header(Header):
row.prop(snode, "backdrop_channels", text="", expand=True)
layout.prop(snode, "use_auto_render")
elif snode.tree_type == 'WorkflowNodeTree':
if snode_id:
row = layout.row()
row.template_ID(snode_id, "node_tree", new="node.new_node_tree")
else:
# Custom node tree is edited as independent ID block
layout.template_ID(snode, "node_tree", new="node.new_node_tree")

View File

@@ -451,6 +451,7 @@ class USERPREF_PT_system(Panel):
col.label(text="Anisotropic Filtering")
col.prop(system, "anisotropic_filter", text="")
col.prop(system, "use_vertex_buffer_objects")
col.prop(system, "use_viewport_new")
col.separator()

View File

@@ -267,7 +267,8 @@ shader_node_categories = [
NodeItem("ShaderNodeBlackbody"),
]),
ShaderNewNodeCategory("SH_NEW_SCRIPT", "Script", items=[
NodeItem("ShaderNodeScript"),
NodeItem("ShaderNodeScript"), # OSL
NodeItem("ShaderNodeScriptGLSL"),
]),
ShaderNewNodeCategory("SH_NEW_GROUP", "Group", items=node_group_items),
ShaderNewNodeCategory("SH_NEW_LAYOUT", "Layout", items=[

View File

@@ -96,6 +96,7 @@ struct MCol;
struct ColorBand;
struct GPUVertexAttribs;
struct GPUDrawObject;
struct GPUxBatch;
struct BMEditMesh;
struct PBVH;
@@ -184,6 +185,7 @@ struct DerivedMesh {
int deformedOnly; /* set by modifier stack if only deformed from original */
BVHCache bvhCache;
struct GPUDrawObject *drawObject;
struct GPUxBatch *gpux_batch; /* TODO: replace with list of batches */
DerivedMeshType type;
float auto_bump_scale;
DMDirtyFlag dirty;
@@ -470,6 +472,10 @@ struct DerivedMesh {
void (*setMaterial)(void *userData, int matnr, void *attribs),
bool (*setFace)(void *userData, int index), void *userData);
struct GPUDrawObject *(*gpuObjectNew)(DerivedMesh *dm);
void (*copy_gpu_data)(DerivedMesh *dm, int type, float *varray, int *index,
int *mat_orig_to_new, void *user_data);
/** Release reference to the DerivedMesh. This function decides internally
* if the DerivedMesh will be freed, or cached for later use. */
void (*release)(DerivedMesh *dm);

View File

@@ -71,7 +71,7 @@ void id_clear_lib_data(struct Main *bmain, struct ID *id);
struct ListBase *which_libbase(struct Main *mainlib, short type);
#define MAX_LIBARRAY 35
#define MAX_LIBARRAY 36
int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
void BKE_libblock_free(struct Main *bmain, void *idv);

View File

@@ -94,6 +94,7 @@ typedef struct Main {
ListBase movieclip;
ListBase mask;
ListBase linestyle;
ListBase gpuworkflows;
char id_tag_update[256];

View File

@@ -231,8 +231,8 @@ void BKE_mesh_normals_loop_custom_from_vertices_set(
short (*r_clnors_data)[2]);
void BKE_mesh_calc_poly_normal(
struct MPoly *mpoly, struct MLoop *loopstart,
struct MVert *mvarray, float no[3]);
const struct MPoly *mpoly, const struct MLoop *loopstart,
const struct MVert *mvarray, float no[3]);
void BKE_mesh_calc_poly_normal_coords(
struct MPoly *mpoly, struct MLoop *loopstart,
const float (*vertex_coords)[3], float no[3]);

View File

@@ -45,6 +45,7 @@
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_view3d_types.h"
#include "RNA_types.h"
@@ -258,8 +259,9 @@ typedef struct bNodeType {
#define NODE_CLASS_LAYOUT 100
/* nodetype->compatibility */
#define NODE_OLD_SHADING 1
#define NODE_NEW_SHADING 2
#define NODE_OLD_SHADING 1
#define NODE_NEW_SHADING 2
#define NODE_WORKFLOW_SHADING 3
/* node resize directions */
#define NODE_RESIZE_TOP 1
@@ -663,6 +665,7 @@ struct NodeTreeIterStore {
Lamp *lamp;
World *world;
FreestyleLineStyle *linestyle;
GPUWorkflowShader *wfshader;
};
void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *bmain);
@@ -782,6 +785,7 @@ struct ShadeResult;
#define SH_NODE_COMBXYZ 189
#define SH_NODE_OUTPUT_LINESTYLE 190
#define SH_NODE_UVALONGSTROKE 191
#define SH_NODE_SCRIPT_GLSL 192
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1

View File

@@ -0,0 +1,43 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Antony Riakiotakis.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef BKE_WORKFLOW_SHADERS_H
#define BKE_WORKFLOW_SHADERS_H
/** \file BKE_workflow_shaders.h
* \ingroup bke
* \since March 2015
* \author psy-fi
*/
struct GPUWorkflowShader;
struct Main;
void BKE_workflow_shader_free(struct GPUWorkflowShader *shader);
struct GPUWorkflowShader *BKE_workflow_shader_add(struct Main *bmain, const char *name);
#endif // BKE_WORKFLOW_SHADERS_H

View File

@@ -174,6 +174,7 @@ set(SRC
intern/tracking_stabilize.c
intern/tracking_util.c
intern/unit.c
intern/workflow_shaders.c
intern/world.c
intern/writeavi.c
intern/writeframeserver.c
@@ -274,6 +275,7 @@ set(SRC
BKE_tracking.h
BKE_unit.h
BKE_utildefines.h
BKE_workflow_shaders.h
BKE_world.h
BKE_writeavi.h
BKE_writeframeserver.h

View File

@@ -75,6 +75,7 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
#include "GPU_buffers.h"
#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "GPUx_draw.h"
/* very slow! enable for testing only! */
//#define USE_MODIFIER_VALIDATE
@@ -337,6 +338,12 @@ int DM_release(DerivedMesh *dm)
if (dm->needsFree) {
bvhcache_free(&dm->bvhCache);
GPU_drawobject_free(dm);
if (dm->gpux_batch) {
GPUx_batch_discard(dm->gpux_batch);
dm->gpux_batch = NULL;
}
CustomData_free(&dm->vertData, dm->numVertData);
CustomData_free(&dm->edgeData, dm->numEdgeData);
CustomData_free(&dm->faceData, dm->numTessFaceData);

View File

@@ -553,6 +553,10 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
NodeShaderScript *nss = (NodeShaderScript *)node->storage;
rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data);
}
else if (node->type == SH_NODE_SCRIPT_GLSL) {
NodeShaderScriptGLSL *nss = (NodeShaderScriptGLSL *)node->storage;
rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data);
}
}
}
break;
@@ -562,7 +566,7 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
bNodeTree *ntree = (bNodeTree *)id;
bNode *node;
if (ntree->type == NTREE_SHADER) {
if (ELEM(ntree->type, NTREE_SHADER, NTREE_WORKFLOW)) {
/* same as lines above */
for (node = ntree->nodes.first; node; node = node->next) {
if (node->type == SH_NODE_SCRIPT) {

View File

@@ -395,7 +395,7 @@ static void cdDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdg
MEdge *medge = cddm->medge;
int i;
int prevstart = 0;
int prevdraw = 1;
bool prevdraw = true;
bool draw = true;
if (cddm->pbvh && cddm->pbvh_draw &&
@@ -417,14 +417,14 @@ static void cdDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdg
draw = false;
}
if (prevdraw != draw) {
if (prevdraw > 0 && (i - prevstart) > 0) {
if (prevdraw && (i - prevstart) > 0) {
GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, prevstart * 2, (i - prevstart) * 2);
}
prevstart = i;
}
prevdraw = draw;
}
if (prevdraw > 0 && (i - prevstart) > 0) {
if (prevdraw && (i - prevstart) > 0) {
GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, prevstart * 2, (i - prevstart) * 2);
}
GPU_buffer_unbind();
@@ -1351,6 +1351,488 @@ static void cdDM_drawMappedEdges(DerivedMesh *dm, DMSetDrawOptions setDrawOption
glEnd();
}
static void cdDM_buffer_copy_vertex(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
{
MVert *mvert;
MFace *f;
int i, j, start, totface;
mvert = dm->getVertArray(dm);
f = dm->getTessFaceArray(dm);
totface = dm->getNumTessFaces(dm);
for (i = 0; i < totface; i++, f++) {
start = index[mat_orig_to_new[f->mat_nr]];
/* v1 v2 v3 */
copy_v3_v3(&varray[start], mvert[f->v1].co);
copy_v3_v3(&varray[start + 3], mvert[f->v2].co);
copy_v3_v3(&varray[start + 6], mvert[f->v3].co);
index[mat_orig_to_new[f->mat_nr]] += 9;
if (f->v4) {
/* v3 v4 v1 */
copy_v3_v3(&varray[start + 9], mvert[f->v3].co);
copy_v3_v3(&varray[start + 12], mvert[f->v4].co);
copy_v3_v3(&varray[start + 15], mvert[f->v1].co);
index[mat_orig_to_new[f->mat_nr]] += 9;
}
}
/* copy loose points */
j = dm->drawObject->tot_triangle_point * 3;
for (i = 0; i < dm->drawObject->totvert; i++) {
if (dm->drawObject->vert_points[i].point_index >= dm->drawObject->tot_triangle_point) {
copy_v3_v3(&varray[j], mvert[i].co);
j += 3;
}
}
}
static void cdDM_buffer_copy_normal(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
{
int i, totface;
int start;
float f_no[3];
const float *nors = dm->getTessFaceDataArray(dm, CD_NORMAL);
short (*tlnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
MVert *mvert = dm->getVertArray(dm);
MFace *f = dm->getTessFaceArray(dm);
totface = dm->getNumTessFaces(dm);
for (i = 0; i < totface; i++, f++) {
const int smoothnormal = (f->flag & ME_SMOOTH);
start = index[mat_orig_to_new[f->mat_nr]];
index[mat_orig_to_new[f->mat_nr]] += f->v4 ? 18 : 9;
if (tlnors) {
short (*tlnor)[3] = tlnors[i];
/* Copy loop normals */
normal_short_to_float_v3(&varray[start], tlnor[0]);
normal_short_to_float_v3(&varray[start + 3], tlnor[1]);
normal_short_to_float_v3(&varray[start + 6], tlnor[2]);
if (f->v4) {
normal_short_to_float_v3(&varray[start + 9], tlnor[2]);
normal_short_to_float_v3(&varray[start + 12], tlnor[3]);
normal_short_to_float_v3(&varray[start + 15], tlnor[0]);
}
}
else if (smoothnormal) {
/* copy vertex normal */
normal_short_to_float_v3(&varray[start], mvert[f->v1].no);
normal_short_to_float_v3(&varray[start + 3], mvert[f->v2].no);
normal_short_to_float_v3(&varray[start + 6], mvert[f->v3].no);
if (f->v4) {
normal_short_to_float_v3(&varray[start + 9], mvert[f->v3].no);
normal_short_to_float_v3(&varray[start + 12], mvert[f->v4].no);
normal_short_to_float_v3(&varray[start + 15], mvert[f->v1].no);
}
}
else if (nors) {
/* copy cached face normal */
copy_v3_v3(&varray[start], &nors[i * 3]);
copy_v3_v3(&varray[start + 3], &nors[i * 3]);
copy_v3_v3(&varray[start + 6], &nors[i * 3]);
if (f->v4) {
copy_v3_v3(&varray[start + 9], &nors[i * 3]);
copy_v3_v3(&varray[start + 12], &nors[i * 3]);
copy_v3_v3(&varray[start + 15], &nors[i * 3]);
}
}
else {
/* calculate face normal */
if (f->v4)
normal_quad_v3(f_no, mvert[f->v1].co, mvert[f->v2].co, mvert[f->v3].co, mvert[f->v4].co);
else
normal_tri_v3(f_no, mvert[f->v1].co, mvert[f->v2].co, mvert[f->v3].co);
copy_v3_v3(&varray[start], f_no);
copy_v3_v3(&varray[start + 3], f_no);
copy_v3_v3(&varray[start + 6], f_no);
if (f->v4) {
copy_v3_v3(&varray[start + 9], f_no);
copy_v3_v3(&varray[start + 12], f_no);
copy_v3_v3(&varray[start + 15], f_no);
}
}
}
}
static void cdDM_buffer_copy_uv(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
{
int start;
int i, totface;
MTFace *mtface;
MFace *f;
if (!(mtface = DM_get_tessface_data_layer(dm, CD_MTFACE)))
return;
f = dm->getTessFaceArray(dm);
totface = dm->getNumTessFaces(dm);
for (i = 0; i < totface; i++, f++) {
start = index[mat_orig_to_new[f->mat_nr]];
/* v1 v2 v3 */
copy_v2_v2(&varray[start], mtface[i].uv[0]);
copy_v2_v2(&varray[start + 2], mtface[i].uv[1]);
copy_v2_v2(&varray[start + 4], mtface[i].uv[2]);
index[mat_orig_to_new[f->mat_nr]] += 6;
if (f->v4) {
/* v3 v4 v1 */
copy_v2_v2(&varray[start + 6], mtface[i].uv[2]);
copy_v2_v2(&varray[start + 8], mtface[i].uv[3]);
copy_v2_v2(&varray[start + 10], mtface[i].uv[0]);
index[mat_orig_to_new[f->mat_nr]] += 6;
}
}
}
static void cdDM_buffer_copy_uv_texpaint(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
{
int start;
int i, totface;
int totmaterial = dm->totmat;
MTFace **mtface_base;
MTFace *stencil_base;
int stencil;
MFace *mf;
/* should have been checked for before, reassert */
BLI_assert(DM_get_tessface_data_layer(dm, CD_MTFACE));
mf = dm->getTessFaceArray(dm);
mtface_base = MEM_mallocN(totmaterial * sizeof(*mtface_base), "texslots");
for (i = 0; i < totmaterial; i++) {
mtface_base[i] = DM_paint_uvlayer_active_get(dm, i);
}
stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE);
stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil);
totface = dm->getNumTessFaces(dm);
for (i = 0; i < totface; i++, mf++) {
int mat_i = mf->mat_nr;
start = index[mat_orig_to_new[mat_i]];
/* v1 v2 v3 */
copy_v2_v2(&varray[start], mtface_base[mat_i][i].uv[0]);
copy_v2_v2(&varray[start + 2], stencil_base[i].uv[0]);
copy_v2_v2(&varray[start + 4], mtface_base[mat_i][i].uv[1]);
copy_v2_v2(&varray[start + 6], stencil_base[i].uv[1]);
copy_v2_v2(&varray[start + 8], mtface_base[mat_i][i].uv[2]);
copy_v2_v2(&varray[start + 10], stencil_base[i].uv[2]);
index[mat_orig_to_new[mat_i]] += 12;
if (mf->v4) {
/* v3 v4 v1 */
copy_v2_v2(&varray[start + 12], mtface_base[mat_i][i].uv[2]);
copy_v2_v2(&varray[start + 14], stencil_base[i].uv[2]);
copy_v2_v2(&varray[start + 16], mtface_base[mat_i][i].uv[3]);
copy_v2_v2(&varray[start + 18], stencil_base[i].uv[3]);
copy_v2_v2(&varray[start + 20], mtface_base[mat_i][i].uv[0]);
copy_v2_v2(&varray[start + 22], stencil_base[i].uv[0]);
index[mat_orig_to_new[mat_i]] += 12;
}
}
MEM_freeN(mtface_base);
}
static void copy_mcol_uc3(unsigned char *v, unsigned char *col)
{
v[0] = col[3];
v[1] = col[2];
v[2] = col[1];
}
/* treat varray_ as an array of MCol, four MCol's per face */
static void cdDM_buffer_copy_mcol(DerivedMesh *dm, float *varray_, int *index, int *mat_orig_to_new, void *user)
{
int i, totface;
unsigned char *varray = (unsigned char *)varray_;
unsigned char *mcol = (unsigned char *)user;
MFace *f = dm->getTessFaceArray(dm);
totface = dm->getNumTessFaces(dm);
for (i = 0; i < totface; i++, f++) {
int start = index[mat_orig_to_new[f->mat_nr]];
/* v1 v2 v3 */
copy_mcol_uc3(&varray[start], &mcol[i * 16]);
copy_mcol_uc3(&varray[start + 3], &mcol[i * 16 + 4]);
copy_mcol_uc3(&varray[start + 6], &mcol[i * 16 + 8]);
index[mat_orig_to_new[f->mat_nr]] += 9;
if (f->v4) {
/* v3 v4 v1 */
copy_mcol_uc3(&varray[start + 9], &mcol[i * 16 + 8]);
copy_mcol_uc3(&varray[start + 12], &mcol[i * 16 + 12]);
copy_mcol_uc3(&varray[start + 15], &mcol[i * 16]);
index[mat_orig_to_new[f->mat_nr]] += 9;
}
}
}
static void cdDM_buffer_copy_edge(DerivedMesh *dm, float *varray_, int *UNUSED(index), int *UNUSED(mat_orig_to_new), void *UNUSED(user))
{
MEdge *medge;
unsigned int *varray = (unsigned int *)varray_;
int i, totedge;
medge = dm->getEdgeArray(dm);
totedge = dm->getNumEdges(dm);
for (i = 0; i < totedge; i++, medge++) {
varray[i * 2] = dm->drawObject->vert_points[medge->v1].point_index;
varray[i * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
}
}
static void cdDM_buffer_copy_uvedge(DerivedMesh *dm, float *varray, int *UNUSED(index), int *UNUSED(mat_orig_to_new), void *UNUSED(user))
{
MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
int i, j = 0;
if (!tf)
return;
for (i = 0; i < dm->numTessFaceData; i++, tf++) {
MFace mf;
dm->getTessFace(dm, i, &mf);
copy_v2_v2(&varray[j], tf->uv[0]);
copy_v2_v2(&varray[j + 2], tf->uv[1]);
copy_v2_v2(&varray[j + 4], tf->uv[1]);
copy_v2_v2(&varray[j + 6], tf->uv[2]);
if (!mf.v4) {
copy_v2_v2(&varray[j + 8], tf->uv[2]);
copy_v2_v2(&varray[j + 10], tf->uv[0]);
j += 12;
}
else {
copy_v2_v2(&varray[j + 8], tf->uv[2]);
copy_v2_v2(&varray[j + 10], tf->uv[3]);
copy_v2_v2(&varray[j + 12], tf->uv[3]);
copy_v2_v2(&varray[j + 14], tf->uv[0]);
j += 16;
}
}
}
static void cdDM_copy_gpu_data(DerivedMesh *dm, int type, float *varray, int *index,
int *mat_orig_to_new, void *user_data)
{
switch(type) {
case GPU_BUFFER_VERTEX:
cdDM_buffer_copy_vertex(dm, varray, index, mat_orig_to_new, user_data);
break;
case GPU_BUFFER_NORMAL:
cdDM_buffer_copy_normal(dm, varray, index, mat_orig_to_new, user_data);
break;
case GPU_BUFFER_COLOR:
cdDM_buffer_copy_mcol(dm, varray, index, mat_orig_to_new, user_data);
break;
case GPU_BUFFER_UV:
cdDM_buffer_copy_uv(dm, varray, index, mat_orig_to_new, user_data);
break;
case GPU_BUFFER_UV_TEXPAINT:
cdDM_buffer_copy_uv_texpaint(dm, varray, index, mat_orig_to_new, user_data);
break;
case GPU_BUFFER_EDGE:
cdDM_buffer_copy_edge(dm, varray, index, mat_orig_to_new, user_data);
break;
case GPU_BUFFER_UVEDGE:
cdDM_buffer_copy_uvedge(dm, varray, index, mat_orig_to_new, user_data);
break;
default:
break;
}
}
/* add a new point to the list of points related to a particular
* vertex */
#ifdef USE_GPU_POINT_LINK
static void cdDM_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index)
{
GPUVertPointLink *lnk;
lnk = &gdo->vert_points[vert_index];
/* if first link is in use, add a new link at the end */
if (lnk->point_index != -1) {
/* get last link */
for (; lnk->next; lnk = lnk->next) ;
/* add a new link from the pool */
lnk = lnk->next = &gdo->vert_points_mem[gdo->vert_points_usage];
gdo->vert_points_usage++;
}
lnk->point_index = point_index;
}
#else
static void cdDM_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index)
{
GPUVertPointLink *lnk;
lnk = &gdo->vert_points[vert_index];
if (lnk->point_index == -1) {
lnk->point_index = point_index;
}
}
#endif /* USE_GPU_POINT_LINK */
/* update the vert_points and triangle_to_mface fields with a new
* triangle */
static void cdDM_drawobject_add_triangle(GPUDrawObject *gdo,
int base_point_index,
int face_index,
int v1, int v2, int v3)
{
int i, v[3] = {v1, v2, v3};
for (i = 0; i < 3; i++)
cdDM_drawobject_add_vert_point(gdo, v[i], base_point_index + i);
gdo->triangle_to_mface[base_point_index / 3] = face_index;
}
/* for each vertex, build a list of points related to it; these lists
* are stored in an array sized to the number of vertices */
static void cdDM_drawobject_init_vert_points(GPUDrawObject *gdo, MFace *f, int totface, int totmat)
{
GPUBufferMaterial *mat;
int i, *mat_orig_to_new;
mat_orig_to_new = MEM_callocN(sizeof(*mat_orig_to_new) * totmat,
"GPUDrawObject.mat_orig_to_new");
/* allocate the array and space for links */
gdo->vert_points = MEM_mallocN(sizeof(GPUVertPointLink) * gdo->totvert,
"GPUDrawObject.vert_points");
#ifdef USE_GPU_POINT_LINK
gdo->vert_points_mem = MEM_callocN(sizeof(GPUVertPointLink) * gdo->tot_triangle_point,
"GPUDrawObject.vert_points_mem");
gdo->vert_points_usage = 0;
#endif
/* build a map from the original material indices to the new
* GPUBufferMaterial indices */
for (i = 0; i < gdo->totmaterial; i++)
mat_orig_to_new[gdo->materials[i].mat_nr] = i;
/* -1 indicates the link is not yet used */
for (i = 0; i < gdo->totvert; i++) {
#ifdef USE_GPU_POINT_LINK
gdo->vert_points[i].link = NULL;
#endif
gdo->vert_points[i].point_index = -1;
}
for (i = 0; i < totface; i++, f++) {
mat = &gdo->materials[mat_orig_to_new[f->mat_nr]];
/* add triangle */
cdDM_drawobject_add_triangle(gdo, mat->start + mat->totpoint,
i, f->v1, f->v2, f->v3);
mat->totpoint += 3;
/* add second triangle for quads */
if (f->v4) {
cdDM_drawobject_add_triangle(gdo, mat->start + mat->totpoint,
i, f->v3, f->v4, f->v1);
mat->totpoint += 3;
}
}
/* map any unused vertices to loose points */
for (i = 0; i < gdo->totvert; i++) {
if (gdo->vert_points[i].point_index == -1) {
gdo->vert_points[i].point_index = gdo->tot_triangle_point + gdo->tot_loose_point;
gdo->tot_loose_point++;
}
}
MEM_freeN(mat_orig_to_new);
}
/* see GPUDrawObject's structure definition for a description of the
* data being initialized here */
static GPUDrawObject *cdDM_GPUobject_new(DerivedMesh *dm)
{
GPUDrawObject *gdo;
MFace *mface;
int totmat = dm->totmat;
int *points_per_mat;
int i, curmat, curpoint, totface;
/* object contains at least one material (default included) so zero means uninitialized dm */
BLI_assert(totmat != 0);
mface = dm->getTessFaceArray(dm);
totface = dm->getNumTessFaces(dm);
/* get the number of points used by each material, treating
* each quad as two triangles */
points_per_mat = MEM_callocN(sizeof(*points_per_mat) * totmat, "GPU_drawobject_new.mat_orig_to_new");
for (i = 0; i < totface; i++)
points_per_mat[mface[i].mat_nr] += mface[i].v4 ? 6 : 3;
/* create the GPUDrawObject */
gdo = MEM_callocN(sizeof(GPUDrawObject), "GPUDrawObject");
gdo->totvert = dm->getNumVerts(dm);
gdo->totedge = dm->getNumEdges(dm);
/* count the number of materials used by this DerivedMesh */
for (i = 0; i < totmat; i++) {
if (points_per_mat[i] > 0)
gdo->totmaterial++;
}
/* allocate an array of materials used by this DerivedMesh */
gdo->materials = MEM_mallocN(sizeof(GPUBufferMaterial) * gdo->totmaterial,
"GPUDrawObject.materials");
/* initialize the materials array */
for (i = 0, curmat = 0, curpoint = 0; i < totmat; i++) {
if (points_per_mat[i] > 0) {
gdo->materials[curmat].start = curpoint;
gdo->materials[curmat].totpoint = 0;
gdo->materials[curmat].mat_nr = i;
curpoint += points_per_mat[i];
curmat++;
}
}
/* store total number of points used for triangles */
gdo->tot_triangle_point = curpoint;
gdo->triangle_to_mface = MEM_mallocN(sizeof(int) * (gdo->tot_triangle_point / 3),
"GPUDrawObject.triangle_to_mface");
cdDM_drawobject_init_vert_points(gdo, mface, totface, totmat);
MEM_freeN(points_per_mat);
return gdo;
}
static void cdDM_foreachMappedVert(
DerivedMesh *dm,
void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]),
@@ -1565,6 +2047,8 @@ static CDDerivedMesh *cdDM_create(const char *desc)
dm->drawMappedFacesTex = cdDM_drawMappedFacesTex;
dm->drawMappedFacesGLSL = cdDM_drawMappedFacesGLSL;
dm->drawMappedFacesMat = cdDM_drawMappedFacesMat;
dm->copy_gpu_data = cdDM_copy_gpu_data;
dm->gpuObjectNew = cdDM_GPUobject_new;
dm->foreachMappedVert = cdDM_foreachMappedVert;
dm->foreachMappedEdge = cdDM_foreachMappedEdge;

View File

@@ -83,6 +83,7 @@ static IDType idtypes[] = {
{ ID_TE, "Texture", "textures", IDTYPE_FLAGS_ISLINKABLE },
{ ID_TXT, "Text", "texts", IDTYPE_FLAGS_ISLINKABLE },
{ ID_VF, "VFont", "fonts", IDTYPE_FLAGS_ISLINKABLE },
{ ID_GPUWS, "GPUWorkflowShader","workflowshaders", IDTYPE_FLAGS_ISLINKABLE },
{ ID_WO, "World", "worlds", IDTYPE_FLAGS_ISLINKABLE },
{ ID_WM, "WindowManager", "window_managers", 0 },
};

View File

@@ -67,6 +67,7 @@
#include "DNA_vfont_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_world_types.h"
#include "DNA_view3d_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -113,6 +114,7 @@
#include "BKE_scene.h"
#include "BKE_text.h"
#include "BKE_texture.h"
#include "BKE_workflow_shaders.h"
#include "BKE_world.h"
#include "RNA_access.h"
@@ -521,6 +523,8 @@ ListBase *which_libbase(Main *mainlib, short type)
return &(mainlib->palettes);
case ID_PC:
return &(mainlib->paintcurves);
case ID_GPUWS:
return &(mainlib->gpuworkflows);
}
return NULL;
}
@@ -618,6 +622,7 @@ int set_listbasepointers(Main *main, ListBase **lb)
lb[a++] = &(main->library);
lb[a++] = &(main->wm);
lb[a++] = &(main->mask);
lb[a++] = &(main->gpuworkflows);
lb[a] = NULL;
@@ -747,6 +752,9 @@ static ID *alloc_libblock_notest(short type)
case ID_PC:
id = MEM_callocN(sizeof(PaintCurve), "Paint Curve");
break;
case ID_GPUWS:
id = MEM_callocN(sizeof(GPUWorkflowShader), "Workflow Shader");
break;
}
return id;
}
@@ -1035,6 +1043,9 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user)
case ID_PC:
BKE_paint_curve_free((PaintCurve *)id);
break;
case ID_GPUWS:
BKE_workflow_shader_free((GPUWorkflowShader *)id);
break;
}
/* avoid notifying on removed data */

View File

@@ -1629,8 +1629,8 @@ void BKE_mesh_loop_tangents(Mesh *mesh, const char *uvmap, float (*r_looptangent
* computing newell normal.
*
*/
static void mesh_calc_ngon_normal(MPoly *mpoly, MLoop *loopstart,
MVert *mvert, float normal[3])
static void mesh_calc_ngon_normal(const MPoly *mpoly, const MLoop *loopstart,
const MVert *mvert, float normal[3])
{
const int nverts = mpoly->totloop;
const float *v_prev = mvert[loopstart[nverts - 1].v].co;
@@ -1651,8 +1651,8 @@ static void mesh_calc_ngon_normal(MPoly *mpoly, MLoop *loopstart,
}
}
void BKE_mesh_calc_poly_normal(MPoly *mpoly, MLoop *loopstart,
MVert *mvarray, float no[3])
void BKE_mesh_calc_poly_normal(const MPoly *mpoly, const MLoop *loopstart,
const MVert *mvarray, float no[3])
{
if (mpoly->totloop > 4) {
mesh_calc_ngon_normal(mpoly, loopstart, mvarray, no);

View File

@@ -1718,6 +1718,7 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user)
if (ntree->execdata) {
switch (ntree->type) {
case NTREE_SHADER:
case NTREE_WORKFLOW:
ntreeShaderEndExecTree(ntree->execdata);
break;
case NTREE_TEXTURE:
@@ -3579,7 +3580,6 @@ static void registerTextureNodes(void)
{
register_node_type_tex_group();
register_node_type_tex_math();
register_node_type_tex_mix_rgb();
register_node_type_tex_valtorgb();
@@ -3597,6 +3597,7 @@ static void registerTextureNodes(void)
register_node_type_tex_output();
register_node_type_tex_viewer();
register_node_type_sh_script();
register_node_type_sh_script_glsl();
register_node_type_sh_tangent();
register_node_type_sh_normal_map();
register_node_type_sh_hair_info();
@@ -3637,6 +3638,7 @@ void init_nodesystem(void)
register_node_tree_type_cmp();
register_node_tree_type_sh();
register_node_tree_type_workflow();
register_node_tree_type_tex();
register_node_type_frame();
@@ -3701,6 +3703,7 @@ void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *b
ntreeiter->lamp = bmain->lamp.first;
ntreeiter->world = bmain->world.first;
ntreeiter->linestyle = bmain->linestyle.first;
ntreeiter->wfshader = bmain->gpuworkflows.first;
}
bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
bNodeTree **r_nodetree, struct ID **r_id)
@@ -3740,6 +3743,11 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
*r_id = (ID *)ntreeiter->linestyle;
ntreeiter->linestyle = ntreeiter->linestyle->id.next;
}
else if (ntreeiter->wfshader) {
*r_nodetree = ntreeiter->wfshader->nodetree;
*r_id = (ID *)ntreeiter->wfshader;
ntreeiter->wfshader = ntreeiter->wfshader->id.next;
}
else {
return false;
}

View File

@@ -72,6 +72,7 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "GPU_buffers.h"
#include "CCGSubSurf.h"
@@ -1734,12 +1735,25 @@ static void ccgDM_drawLooseEdges(DerivedMesh *dm)
}
}
static void ccgDM_NormalFast(float *a, float *b, float *c, float *d, float no[3])
{
float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
no[0] = b_dY * a_cZ - b_dZ * a_cY;
no[1] = b_dZ * a_cX - b_dX * a_cZ;
no[2] = b_dX * a_cY - b_dY * a_cX;
normalize_v3(no);
}
static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d)
{
float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
float no[3];
no[0] = b_dY * a_cZ - b_dZ * a_cY;
no[1] = b_dZ * a_cX - b_dX * a_cZ;
no[2] = b_dX * a_cY - b_dY * a_cX;
@@ -1748,9 +1762,309 @@ static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d)
glNormal3fv(no);
}
/* Only used by non-editmesh types */
static void ccgDM_prepare_normal_data(DerivedMesh *dm, float *varray, int *vindex,
int *mat_orig_to_new, void *UNUSED(user_data))
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
CCGSubSurf *ss = ccgdm->ss;
CCGKey key;
short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
int gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
DMFlagMat *faceFlags = ccgdm->faceFlags;
int i, totface = ccgSubSurf_getNumFaces(ss);
int matnr, shademodel;
int start;
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
for (i = 0; i < totface; i++) {
CCGFace *f = ccgdm->faceMap[i].face;
int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
short (*ln)[4][3] = NULL;
if (faceFlags) {
shademodel = (lnors || (faceFlags[index].flag & ME_SMOOTH)) ? GL_SMOOTH : GL_FLAT;
matnr = faceFlags[index].mat_nr;
}
else {
shademodel = GL_SMOOTH;
matnr = 0;
}
if (lnors) {
ln = lnors;
lnors += gridFaces * gridFaces * numVerts;
}
for (S = 0; S < numVerts; S++) {
CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
if (ln) {
/* Can't use quad strips here... */
for (y = 0; y < gridFaces; y ++) {
for (x = 0; x < gridFaces; x ++) {
start = vindex[mat_orig_to_new[matnr]];
normal_short_to_float_v3(&varray[start], ln[0][1]);
normal_short_to_float_v3(&varray[start + 3], ln[0][2]);
normal_short_to_float_v3(&varray[start + 6], ln[0][3]);
normal_short_to_float_v3(&varray[start + 9], ln[0][3]);
normal_short_to_float_v3(&varray[start + 12], ln[0][1]);
normal_short_to_float_v3(&varray[start + 15], ln[0][0]);
vindex[mat_orig_to_new[matnr]] += 18;
ln ++;
}
}
}
else if (shademodel == GL_SMOOTH) {
for (y = 0; y < gridFaces; y ++) {
for (x = 0; x < gridFaces; x ++) {
float *a = CCG_grid_elem_no(&key, faceGridData, x, y );
float *b = CCG_grid_elem_no(&key, faceGridData, x + 1, y);
float *c = CCG_grid_elem_no(&key, faceGridData, x + 1, y + 1);
float *d = CCG_grid_elem_no(&key, faceGridData, x, y + 1);
start = vindex[mat_orig_to_new[matnr]];
copy_v3_v3(&varray[start], d);
copy_v3_v3(&varray[start + 3], c);
copy_v3_v3(&varray[start + 6], b);
copy_v3_v3(&varray[start + 9], d);
copy_v3_v3(&varray[start + 12], b);
copy_v3_v3(&varray[start + 15], a);
vindex[mat_orig_to_new[matnr]] += 18;
}
}
}
else {
for (y = 0; y < gridFaces; y ++) {
for (x = 0; x < gridFaces; x ++) {
float no[3];
float *a = CCG_grid_elem_co(&key, faceGridData, x, y );
float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y );
float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
ccgDM_NormalFast(a, b, c, d, no);
start = vindex[mat_orig_to_new[matnr]];
copy_v3_v3(&varray[start], no);
copy_v3_v3(&varray[start + 3], no);
copy_v3_v3(&varray[start + 6], no);
copy_v3_v3(&varray[start + 9], no);
copy_v3_v3(&varray[start + 12], no);
copy_v3_v3(&varray[start + 15], no);
vindex[mat_orig_to_new[matnr]] += 18;
}
}
}
}
}
}
/* Only used by non-editmesh types */
static void ccgDM_prepare_vertex_data(DerivedMesh *dm, float *varray, int *vindex,
int *mat_orig_to_new, void *UNUSED(user_data))
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
CCGSubSurf *ss = ccgdm->ss;
CCGKey key;
int gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
DMFlagMat *faceFlags = ccgdm->faceFlags;
int i, totface = ccgSubSurf_getNumFaces(ss);
int matnr = -1, start;
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
for (i = 0; i < totface; i++) {
CCGFace *f = ccgdm->faceMap[i].face;
int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
if (faceFlags) {
matnr = faceFlags[index].mat_nr;
}
else {
matnr = 0;
}
for (S = 0; S < numVerts; S++) {
CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
for (y = 0; y < gridFaces; y++) {
for (x = 0; x < gridFaces; x++) {
float *a = CCG_grid_elem_co(&key, faceGridData, x, y);
float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
start = vindex[mat_orig_to_new[matnr]];
copy_v3_v3(&varray[start], d);
copy_v3_v3(&varray[start + 3], c);
copy_v3_v3(&varray[start + 6], b);
copy_v3_v3(&varray[start + 9], d);
copy_v3_v3(&varray[start + 12], b);
copy_v3_v3(&varray[start + 15], a);
vindex[mat_orig_to_new[matnr]] += 18;
}
}
}
}
}
static void ccgDM_copy_gpu_data(DerivedMesh *dm, int type, float *varray, int *index,
int *mat_orig_to_new, void *UNUSED(user_data))
{
switch(type) {
case GPU_BUFFER_VERTEX:
ccgDM_prepare_vertex_data(dm, varray, index, mat_orig_to_new, NULL);
break;
case GPU_BUFFER_NORMAL:
ccgDM_prepare_normal_data(dm, varray, index, mat_orig_to_new, NULL);
break;
default:
break;
}
}
static GPUDrawObject *ccgDM_GPUObjectNew(DerivedMesh *dm) {
// GPUBufferMaterial *mat;
int *mat_orig_to_new;
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
CCGSubSurf *ss = ccgdm->ss;
GPUDrawObject *gdo;
DMFlagMat *faceFlags = ccgdm->faceFlags;
int gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
int totmat = (faceFlags) ? dm->totmat : 1;
int *points_per_mat;
int i, curmat, curpoint, totface;
/* object contains at least one material (default included) so zero means uninitialized dm */
BLI_assert(totmat != 0);
totface = ccgSubSurf_getNumFaces(ss);
points_per_mat = MEM_callocN(sizeof(*points_per_mat) * totmat, "GPU_drawobject_new.mat_orig_to_new");
if (faceFlags) {
for (i = 0; i < totface; i++) {
CCGFace *f = ccgdm->faceMap[i].face;
int numVerts = ccgSubSurf_getFaceNumVerts(f);
int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
int new_matnr = faceFlags[index].mat_nr;
points_per_mat[new_matnr] += numVerts * gridFaces * gridFaces * 6;
}
}
else {
for (i = 0; i < totface; i++) {
points_per_mat[0] += gridFaces * gridFaces * 6;
}
}
/* create the GPUDrawObject */
gdo = MEM_callocN(sizeof(GPUDrawObject), "GPUDrawObject");
gdo->totvert = ccgSubSurf_getNumFinalFaces(ss) * 6;
gdo->totedge = ccgSubSurf_getNumFinalEdges(ss) * 2;
/* count the number of materials used by this DerivedMesh */
for (i = 0; i < totmat; i++) {
if (points_per_mat[i] > 0)
gdo->totmaterial++;
}
/* allocate an array of materials used by this DerivedMesh */
gdo->materials = MEM_mallocN(sizeof(GPUBufferMaterial) * gdo->totmaterial,
"GPUDrawObject.materials");
/* initialize the materials array */
for (i = 0, curmat = 0, curpoint = 0; i < totmat; i++) {
if (points_per_mat[i] > 0) {
gdo->materials[curmat].start = curpoint;
gdo->materials[curmat].totpoint = points_per_mat[i];
gdo->materials[curmat].mat_nr = i;
curpoint += points_per_mat[i];
curmat++;
}
}
/* store total number of points used for triangles */
gdo->tot_triangle_point = curpoint;
mat_orig_to_new = MEM_callocN(sizeof(*mat_orig_to_new) * totmat,
"GPUDrawObject.mat_orig_to_new");
/* build a map from the original material indices to the new
* GPUBufferMaterial indices */
for (i = 0; i < gdo->totmaterial; i++) {
mat_orig_to_new[gdo->materials[i].mat_nr] = i;
}
/*
for (i = 0; i < totface; i++) {
CCGFace *f = ccgdm->faceMap[i].face;
int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
int new_matnr = faceFlags[index].mat_nr;
mat = &gdo->materials[mat_orig_to_new[new_matnr]];
}
*/
MEM_freeN(mat_orig_to_new);
MEM_freeN(points_per_mat);
return gdo;
}
/* Only used by non-editmesh types */
static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)[4], bool fast, DMSetMaterial setMaterial)
{
int a;
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
if (ccgdm->pbvh && ccgdm->multires.mmd && !fast) {
if (BKE_pbvh_has_faces(ccgdm->pbvh)) {
BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL,
setMaterial, false);
glShadeModel(GL_FLAT);
}
return;
}
GPU_vertex_setup(dm);
GPU_normal_setup(dm);
glShadeModel(GL_SMOOTH);
for (a = 0; a < dm->drawObject->totmaterial; a++) {
if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) {
glDrawArrays(GL_TRIANGLES, dm->drawObject->materials[a].start,
dm->drawObject->materials[a].totpoint);
}
}
GPU_buffer_unbind();
#if 0
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
CCGSubSurf *ss = ccgdm->ss;
CCGKey key;
@@ -1765,15 +2079,6 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
if (ccgdm->pbvh && ccgdm->multires.mmd && !fast) {
if (BKE_pbvh_has_faces(ccgdm->pbvh)) {
BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL,
setMaterial, false);
glShadeModel(GL_FLAT);
}
return;
}
for (i = 0; i < totface; i++) {
CCGFace *f = ccgdm->faceMap[i].face;
@@ -1873,6 +2178,8 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
}
}
}
#endif
}
/* Only used by non-editmesh types */
@@ -3492,6 +3799,8 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->dm.drawMappedEdgesInterp = ccgDM_drawMappedEdgesInterp;
ccgdm->dm.drawMappedEdges = ccgDM_drawMappedEdges;
ccgdm->dm.gpuObjectNew = ccgDM_GPUObjectNew;
ccgdm->dm.copy_gpu_data = ccgDM_copy_gpu_data;
ccgdm->dm.release = ccgDM_release;

View File

@@ -0,0 +1,66 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Antony Riakiotakis.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/workflow_shaders.c
* \ingroup bke
*/
#include "DNA_view3d_types.h"
#include "DNA_object_types.h"
#include "BKE_library.h"
#include "BKE_node.h"
#include "BKE_workflow_shaders.h"
#include "MEM_guardedalloc.h"
void BKE_workflow_shader_free(GPUWorkflowShader *shader)
{
/* is no lib link block, but world extension */
if (shader->nodetree) {
/* will be freed once this is handled properly, currently this resides in nodetree list */
//ntreeFreeTree_ex(shader->nodetree, true);
//MEM_freeN(shader->nodetree);
//shader->nodetree = NULL;
}
}
struct GPUWorkflowShader *BKE_workflow_shader_add(struct Main *bmain, const char *name)
{
GPUWorkflowShader *wfshader;
wfshader = BKE_libblock_alloc(bmain, ID_GPUWS, name);
/* enable fake user by default */
wfshader->id.flag |= LIB_FAKEUSER;
/* initially active only for object mode */
wfshader->objectmode |= OB_MODE_OBJECT;
return wfshader;
}

View File

@@ -2520,6 +2520,7 @@ static bNodeTree *nodetree_from_id(ID *id)
case ID_LA: return ((Lamp *)id)->nodetree;
case ID_TE: return ((Tex *)id)->nodetree;
case ID_LS: return ((FreestyleLineStyle *)id)->nodetree;
case ID_GPUWS: return ((GPUWorkflowShader *)id)->nodetree;
}
return NULL;
}
@@ -2793,7 +2794,7 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
if (node->storage) {
/* could be handlerized at some point */
if (ntree->type==NTREE_SHADER) {
if (ELEM(ntree->type, NTREE_SHADER, NTREE_WORKFLOW)) {
if (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB) {
direct_link_curvemapping(fd, node->storage);
}
@@ -2801,6 +2802,10 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
NodeShaderScript *nss = (NodeShaderScript *) node->storage;
nss->bytecode = newdataadr(fd, nss->bytecode);
}
else if (node->type==SH_NODE_SCRIPT_GLSL) {
NodeShaderScriptGLSL *nss = (NodeShaderScriptGLSL *) node->storage;
/* TODO: whatever */
}
}
else if (ntree->type==NTREE_COMPOSIT) {
if (ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT))
@@ -3085,6 +3090,30 @@ static void direct_link_camera(FileData *fd, Camera *ca)
direct_link_animdata(fd, ca->adt);
}
/*************** READ WORKFLOW SHADER *****************/
static void lib_link_workflow_shader(FileData *fd, Main *main)
{
GPUWorkflowShader *wfshader;
/* only link ID pointers */
for (wfshader = main->gpuworkflows.first; wfshader; wfshader = wfshader->id.next) {
if (wfshader->id.flag & LIB_NEED_LINK) {
wfshader->id.flag -= LIB_NEED_LINK;
if (wfshader->nodetree) {
lib_link_ntree(fd, &wfshader->id, wfshader->nodetree);
wfshader->nodetree->id.lib = wfshader->id.lib;
wfshader->nodetree->view_center[0] = 0.0;
}
}
}
}
static void direct_link_workflow_shader(FileData *fd, GPUWorkflowShader *wfshader)
{
wfshader->nodetree = newdataadr(fd, wfshader->nodetree);
}
/* ************ READ LAMP ***************** */
@@ -5945,6 +5974,7 @@ static void lib_link_screen(FileData *fd, Main *main)
View3D *v3d = (View3D*) sl;
BGpic *bgpic = NULL;
v3d->activeworkflow = newlibadr(fd, sc->id.lib, v3d->activeworkflow);
v3d->camera= newlibadr(fd, sc->id.lib, v3d->camera);
v3d->ob_centre= newlibadr(fd, sc->id.lib, v3d->ob_centre);
@@ -6244,6 +6274,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
if (v3d->camera == NULL)
v3d->camera = sc->scene->camera;
v3d->ob_centre = restore_pointer_by_name(newmain, (ID *)v3d->ob_centre, USER_ONE);
v3d->activeworkflow = restore_pointer_by_name(newmain, (ID *)v3d->activeworkflow, USER_ONE);
for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next) {
if ((bgpic->ima = restore_pointer_by_name(newmain, (ID *)bgpic->ima, USER_IGNORE))) {
@@ -7690,6 +7721,9 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
case ID_PC:
direct_link_paint_curve(fd, (PaintCurve *)id);
break;
case ID_GPUWS:
direct_link_workflow_shader(fd, (GPUWorkflowShader *)id);
break;
}
oldnewmap_free_unused(fd->datamap);
@@ -7877,6 +7911,7 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */
lib_link_brush(fd, main);
lib_link_palette(fd, main);
lib_link_workflow_shader(fd, main);
lib_link_paint_curve(fd, main);
lib_link_particlesettings(fd, main);
lib_link_movieclip(fd, main);

View File

@@ -869,10 +869,11 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
writestruct(wd, DATA, "bNodeLink", 1, link);
if (node->storage) {
/* could be handlerized at some point, now only 1 exception still */
if (ntree->type==NTREE_SHADER && (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB))
if (ELEM(ntree->type, NTREE_SHADER, NTREE_WORKFLOW) && (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB))
write_curvemapping(wd, node->storage);
else if (ntree->type==NTREE_SHADER && node->type==SH_NODE_SCRIPT) {
NodeShaderScript *nss = (NodeShaderScript *)node->storage;
/* XXX merwin: empty GLSL shader node can use the 'else' clause below */
if (nss->bytecode)
writedata(wd, DATA, strlen(nss->bytecode)+1, nss->bytecode);
writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage);
@@ -3182,6 +3183,23 @@ static void write_paintcurves(WriteData *wd, ListBase *idbase)
}
}
static void write_gpuworkflows(WriteData *wd, ListBase *idbase)
{
GPUWorkflowShader *wfshader;
for (wfshader = idbase->first; wfshader; wfshader = wfshader->id.next) {
if (wfshader->id.us > 0 || wd->current) {
writestruct(wd, ID_GPUWS, "GPUWorkflowShader", 1, wfshader);
if (wfshader->nodetree) {
writestruct(wd, DATA, "bNodeTree", 1, wfshader->nodetree);
write_nodetree(wd, wfshader->nodetree);
}
if (wfshader->id.properties) IDP_WriteProperty(wfshader->id.properties, wd);
}
}
}
static void write_scripts(WriteData *wd, ListBase *idbase)
{
Script *script;
@@ -3657,6 +3675,7 @@ static int write_file_handle(
write_brushes (wd, &mainvar->brush);
write_palettes (wd, &mainvar->palettes);
write_paintcurves (wd, &mainvar->paintcurves);
write_gpuworkflows (wd, &mainvar->gpuworkflows);
write_scripts (wd, &mainvar->script);
write_gpencils (wd, &mainvar->gpencil);
write_linestyles(wd, &mainvar->linestyle);

View File

@@ -2949,6 +2949,7 @@ void ED_node_init_butfuncs(void)
ntreeType_Composite->ui_icon = ICON_RENDERLAYERS;
ntreeType_Shader->ui_icon = ICON_MATERIAL;
ntreeType_Texture->ui_icon = ICON_TEXTURE;
ntreeType_Workflow->ui_icon = ICON_SMOOTH;
}
void ED_init_custom_node_type(bNodeType *ntype)

View File

@@ -134,6 +134,9 @@ void ED_node_tag_update_id(ID *id)
else if (GS(id->name) == ID_WO)
WM_main_add_notifier(NC_WORLD | ND_WORLD, id);
}
else if (ntree->type == NTREE_WORKFLOW) {
WM_main_add_notifier(NC_SCENE | ND_NODES, id);
}
else if (ntree->type == NTREE_COMPOSIT) {
WM_main_add_notifier(NC_SCENE | ND_NODES, id);
}

View File

@@ -2372,6 +2372,8 @@ void NODE_OT_tree_socket_move(wmOperatorType *ot)
/* ********************** Shader Script Update ******************/
/* TODO: similar for GLSL node --merwin */
static int node_shader_script_update_poll(bContext *C)
{
Scene *scene = CTX_data_scene(C);

View File

@@ -423,6 +423,9 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
else
compatibility = NODE_OLD_SHADING;
}
else if (ntree->type == NTREE_WORKFLOW) {
compatibility = NODE_WORKFLOW_SHADING;
}
NODE_TYPES_BEGIN(ntype) {
NodeLinkItem *items;

File diff suppressed because it is too large Load Diff

View File

@@ -98,6 +98,7 @@
#include "GPU_material.h"
#include "GPU_extensions.h"
#include "GPU_compositing.h"
#include "GPUx_draw.h"
#include "view3d_intern.h" /* own include */
@@ -557,6 +558,170 @@ static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool wr
glDepthMask(GL_TRUE);
}
static void drawfloor_new(Scene *scene, View3D *v3d, const char **grid_unit)
{
/* draw only if there is something to draw */
if (v3d->gridflag & (V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z)) {
/* draw how many lines?
* trunc(v3d->gridlines / 2) * 4
* + 2 for xy axes (possibly with special colors)
* + 1 for z axis (the only line not in xy plane)
* even v3d->gridlines are honored, odd rounded down */
const int gridlines = v3d->gridlines / 2;
const float grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit);
const float grid = gridlines * grid_scale;
const bool show_floor = (v3d->gridflag & V3D_SHOW_FLOOR) && gridlines >= 1;
unsigned char col_grid[3], col_axis[3];
UI_GetThemeColor3ubv(TH_GRID, col_grid);
if (show_floor) {
const unsigned vertex_ct = 2 * (gridlines * 4 + 2);
unsigned v = 0; /* verts drawn so far */
VertexBuffer *verts = GPUx_vertex_buffer_create(2, vertex_ct);
const int sublines = v3d->gridsubdiv;
int a;
unsigned char col_bg[3], col_grid_emphasise[3], col_grid_light[3];
unsigned char *col_current = NULL;
GPUx_specify_attrib(verts, 0, GL_VERTEX_ARRAY, GL_FLOAT, 2, KEEP_FLOAT);
GPUx_specify_attrib(verts, 1, GL_COLOR_ARRAY, GL_UNSIGNED_BYTE, 3, NORMALIZE_INT_TO_FLOAT);
glDepthFunc(GL_ALWAYS); /* draw lines in order given */
/* draw normal grid lines */
UI_GetColorPtrShade3ubv(col_grid, col_grid_light, 10);
col_current = col_grid_light;
for (a = 1; a <= gridlines; a++) {
/* skip emphasised divider lines */
if (a % sublines != 0) {
const float line = a * grid_scale;
int i;
/* same color at each vertex */
for (i = 0; i < 8; ++i)
GPUx_set_attrib(verts, 1, v + i, col_current);
/* set positions */
GPUx_set_attrib_2f(verts, 0, v + 0, -grid, -line);
GPUx_set_attrib_2f(verts, 0, v + 1, +grid, -line);
GPUx_set_attrib_2f(verts, 0, v + 2, -grid, +line);
GPUx_set_attrib_2f(verts, 0, v + 3, +grid, +line);
GPUx_set_attrib_2f(verts, 0, v + 4, -line, -grid);
GPUx_set_attrib_2f(verts, 0, v + 5, -line, +grid);
GPUx_set_attrib_2f(verts, 0, v + 6, +line, -grid);
GPUx_set_attrib_2f(verts, 0, v + 7, +line, +grid);
v += 8;
}
}
/* draw emphasised grid lines */
UI_GetThemeColor3ubv(TH_BACK, col_bg);
/* emphasise division lines lighter instead of darker, if background is darker than grid */
UI_GetColorPtrShade3ubv(col_grid, col_grid_emphasise,
(col_grid[0] + col_grid[1] + col_grid[2] + 30 >
col_bg[0] + col_bg[1] + col_bg[2]) ? 20 : -10);
col_current = col_grid_emphasise;
for (a = sublines; a <= gridlines; a += sublines) {
const float line = a * grid_scale;
int i;
/* same color at each vertex */
for (i = 0; i < 8; ++i)
GPUx_set_attrib(verts, 1, v + i, col_current);
/* set positions */
GPUx_set_attrib_2f(verts, 0, v + 0, -grid, -line);
GPUx_set_attrib_2f(verts, 0, v + 1, +grid, -line);
GPUx_set_attrib_2f(verts, 0, v + 2, -grid, +line);
GPUx_set_attrib_2f(verts, 0, v + 3, +grid, +line);
GPUx_set_attrib_2f(verts, 0, v + 4, -line, -grid);
GPUx_set_attrib_2f(verts, 0, v + 5, -line, +grid);
GPUx_set_attrib_2f(verts, 0, v + 6, +line, -grid);
GPUx_set_attrib_2f(verts, 0, v + 7, +line, +grid);
v += 8;
}
/* draw X axis */
if (v3d->gridflag & V3D_SHOW_X) {
UI_make_axis_color(col_grid, col_axis, 'X');
col_current = col_axis;
}
else
col_current = col_grid_emphasise;
GPUx_set_attrib(verts, 1, v + 0, col_current);
GPUx_set_attrib(verts, 1, v + 1, col_current);
GPUx_set_attrib_2f(verts, 0, v + 0, -grid, 0.0f);
GPUx_set_attrib_2f(verts, 0, v + 1, +grid, 0.0f);
/* draw Y axis */
if (v3d->gridflag & V3D_SHOW_Y) {
UI_make_axis_color(col_grid, col_axis, 'Y');
col_current = col_axis;
}
else
col_current = col_grid_emphasise;
GPUx_set_attrib(verts, 1, v + 2, col_current);
GPUx_set_attrib(verts, 1, v + 3, col_current);
GPUx_set_attrib_2f(verts, 0, v + 2, 0.0f, -grid);
GPUx_set_attrib_2f(verts, 0, v + 3, 0.0f, +grid);
v += 4;
BLI_assert(v == vertex_ct);
GPUx_vertex_buffer_prime(verts);
GPUx_draw_lines(verts, NULL, NULL, NULL);
GPUx_vertex_buffer_discard(verts);
/* done with XY plane */
glDepthFunc(GL_LESS); /* restore default */
/* maybe draw Z axis */
if (v3d->gridflag & V3D_SHOW_Z) {
UI_make_axis_color(col_grid, col_axis, 'Z');
glColor3ubv(col_axis);
glBegin(GL_LINES);
glVertex3f(0.0f, 0.0f, -grid);
glVertex3f(0.0f, 0.0f, +grid);
glEnd();
}
}
else {
/* draw just the axis lines */
int axis;
glBegin(GL_LINES);
for (axis = 0; axis < 3; axis++) {
if (v3d->gridflag & (V3D_SHOW_X << axis)) {
float vert[3] = {0.0f};
UI_make_axis_color(col_grid, col_axis, 'X' + axis);
glColor3ubv(col_axis);
vert[axis] = grid;
glVertex3fv(vert);
vert[axis] = -grid;
glVertex3fv(vert);
}
}
glEnd();
}
}
}
static void drawcursor(Scene *scene, ARegion *ar, View3D *v3d)
{
@@ -3693,9 +3858,147 @@ static void update_lods(Scene *scene, float camera_pos[3])
}
#endif
/* uploads and caches view dependent state such as view/projection matrix */
static void view3d_update_view_dependent_uniforms(void)
{
}
static void view3d_main_area_draw_viewport_new(const bContext *UNUSED(C), Scene *scene, View3D *v3d,
ARegion *ar, const char **grid_unit)
{
unsigned int lay_used = 0;
Base *base, *base_edit = NULL; /* object being edited, if any */
bool do_compositing = false;
RegionView3D *rv3d = ar->regiondata;
#if MCE_TRACE
printf("> %s\n", __FUNCTION__);
#endif /* MCE_TRACE */
view3d_main_area_clear(scene, v3d, ar);
/* setup view matrices */
view3d_main_area_setup_view(scene, v3d, ar, NULL, NULL);
view3d_update_view_dependent_uniforms();
/* framebuffer fx needed, we need to draw offscreen first */
if (v3d->fx_settings.fx_flag) {
GPUFXSettings fx_settings;
BKE_screen_gpu_fx_validate(&v3d->fx_settings);
fx_settings = v3d->fx_settings;
if (!rv3d->compositor)
rv3d->compositor = GPU_fx_compositor_create();
if (rv3d->persp == RV3D_CAMOB && v3d->camera)
BKE_camera_to_gpu_dof(v3d->camera, &fx_settings);
else {
fx_settings.dof = NULL;
}
if (v3d->drawtype < OB_SOLID)
fx_settings.ssao = NULL;
do_compositing = GPU_fx_compositor_initialize_passes(rv3d->compositor, &ar->winrct, &ar->drawrct, &fx_settings);
}
/* clear the background */
view3d_main_area_clear(scene, v3d, ar);
GPUx_reset_draw_state(); /* for code below which uses GPUx_state */
drawfloor_new(scene, v3d, grid_unit);
/* yanked verbatim from view3d_draw_objects
* not perfect but it does let us see objects positioned in space
* TODO: draw objects prettier/better/faster/stronger
*/
/* XXX merwin
*
* Instead of drawing all objects in list order, draw all meshes together
* using new methods, then other types using new methods, then remaining
* types using existing methods.
*
* Hand-crafted logic here is tricky; will simplify later.
*/
v3d->zbuf = true;
/* draw meshes (and cameras) not being edited (selected or not) */
for (base = scene->base.first; base; base = base->next) {
lay_used |= base->lay;
if (base->object == scene->obedit) {
base_edit = base; /* remember for later */
continue;
}
if (v3d->lay & base->lay) {
if (base->object->type == OB_MESH || base->object->type == OB_CAMERA) {
draw_object_new(scene, ar, v3d, base, 0);
}
}
}
GPUx_reset_draw_state(); /* for code below which does NOT use GPUx_state */
/* draw non-meshes not being edited nor selected */
for (base = scene->base.first; base; base = base->next) {
if (base == base_edit)
continue;
if (v3d->lay & base->lay) {
if (base->object->type != OB_MESH && base->object->type != OB_CAMERA && (base->flag & SELECT) == 0) {
draw_object(scene, ar, v3d, base, 0);
}
}
}
/* mask out localview */
v3d->lay_used = lay_used & ((1 << 20) - 1);
/* draw selected non-meshes */
for (base = scene->base.first; base; base = base->next) {
if (base == base_edit)
continue;
if (v3d->lay & base->lay) {
if (base->object->type != OB_MESH && base->object->type != OB_CAMERA && (base->flag & SELECT)) {
draw_object(scene, ar, v3d, base, 0);
}
}
}
/* draw editmode */
/* TODO: verify scene->obedit is always 1) selected and 2) in a visible layer */
if (base_edit && (v3d->lay & base_edit->lay)) {
draw_object(scene, ar, v3d, base_edit, 0);
}
/* post process */
if (do_compositing) {
GPU_fx_do_composite_pass(rv3d->compositor, rv3d->winmat, rv3d->is_persp, scene, NULL);
}
/* play nice with UI drawing code outside view3d */
glDisable(GL_DEPTH_TEST);
#if MCE_TRACE
printf("< %s\n\n", __FUNCTION__);
#endif /* MCE_TRACE */
}
static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3D *v3d,
ARegion *ar, const char **grid_unit)
{
#if MCE_TRACE
printf("> %s\n", __FUNCTION__);
#endif /* MCE_TRACE */
RegionView3D *rv3d = ar->regiondata;
unsigned int lay_used = v3d->lay_used;
@@ -3781,6 +4084,9 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3
/* TODO: draw something else (but not this) during fly mode */
draw_rotation_guide(rv3d);
#if MCE_TRACE
printf("< %s\n\n", __FUNCTION__);
#endif /* MCE_TRACE */
}
static bool is_cursor_visible(Scene *scene)
@@ -3906,8 +4212,11 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar)
/* draw viewport using opengl */
if (v3d->drawtype != OB_RENDER || !view3d_main_area_do_render_draw(scene) || clip_border) {
view3d_main_area_draw_objects(C, scene, v3d, ar, &grid_unit);
if (U.gameflags & USER_VIEWPORT_2)
view3d_main_area_draw_viewport_new(C, scene, v3d, ar, &grid_unit);
else {
view3d_main_area_draw_objects(C, scene, v3d, ar, &grid_unit);
}
#ifdef DEBUG_DRAW
bl_debug_draw();
#endif

View File

@@ -44,6 +44,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_main.h"
#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_font.h"
@@ -55,7 +56,7 @@
#include "BKE_screen.h"
#include "BKE_action.h"
#include "BKE_depsgraph.h" /* for ED_view3d_camera_lock_sync */
#include "BKE_workflow_shaders.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -5124,3 +5125,32 @@ void ED_view3D_lock_clear(View3D *v3d)
v3d->ob_centre_cursor = false;
v3d->flag2 &= ~V3D_LOCK_CAMERA;
}
/**** Workflow Shaders ******************/
static int view3d_workflow_new_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
View3D *v3d = CTX_wm_view3d(C);
GPUWorkflowShader *wfshader = BKE_workflow_shader_add(bmain, "Workflow Shader");
if (v3d)
v3d->activeworkflow = wfshader;
return OPERATOR_FINISHED;
}
void VIEW3D_OT_workflow_new(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "New Workflow Shader";
ot->description = "Creates a new workflow shader";
ot->idname = "VIEW3D_OT_workflow_new";
/* api callbacks */
ot->exec = view3d_workflow_new_exec;
/* flags */
ot->flag = 0;
}

View File

@@ -330,7 +330,11 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
}
/* Draw type */
uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
if (U.gameflags & USER_VIEWPORT_2)
/* TODO add something for unlinking */
uiTemplateID(layout, C, &v3dptr, "activeworkflow", "VIEW3D_OT_workflow_new", NULL, NULL);
else
uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
if (obedit == NULL && is_paint) {
if (ob->mode & OB_MODE_ALL_PAINT) {

View File

@@ -51,6 +51,10 @@ struct wmOperatorType;
struct wmWindowManager;
struct wmKeyConfig;
/* temporary function call tracing */
#define MCE_TRACE false
/* TODO: remove --^ */
/* drawing flags: */
enum {
DRAW_PICKING = (1 << 0),
@@ -103,6 +107,7 @@ void VIEW3D_OT_enable_manipulator(struct wmOperatorType *ot);
void VIEW3D_OT_render_border(struct wmOperatorType *ot);
void VIEW3D_OT_clear_render_border(struct wmOperatorType *ot);
void VIEW3D_OT_zoom_border(struct wmOperatorType *ot);
void VIEW3D_OT_workflow_new(struct wmOperatorType *ot);
void view3d_boxview_copy(ScrArea *sa, ARegion *ar);
@@ -133,6 +138,7 @@ void draw_motion_paths_cleanup(View3D *v3d);
/* drawobject.c */
void draw_object(Scene *scene, struct ARegion *ar, View3D *v3d, Base *base, const short dflag);
void draw_object_new(Scene *scene, struct ARegion *ar, View3D *v3d, Base *base, const short dflag);
bool draw_glsl_material(Scene *scene, struct Object *ob, View3D *v3d, const char dt);
void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob, const char dt, int outline);
void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob);

View File

@@ -161,6 +161,7 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_view_center_pick);
WM_operatortype_append(VIEW3D_OT_view_center_camera);
WM_operatortype_append(VIEW3D_OT_view_center_lock);
WM_operatortype_append(VIEW3D_OT_workflow_new);
WM_operatortype_append(VIEW3D_OT_select);
WM_operatortype_append(VIEW3D_OT_select_border);
WM_operatortype_append(VIEW3D_OT_clip_border);

View File

@@ -56,6 +56,10 @@ set(SRC
intern/gpu_select.c
intern/gpu_compositing.c
intern/gpu_debug.c
intern/gpux_element.c
intern/gpux_draw.c
intern/gpux_vbo.c
intern/gpux_state.c
shaders/gpu_program_smoke_frag.glsl
shaders/gpu_program_smoke_color_frag.glsl
@@ -88,8 +92,13 @@ set(SRC
GPU_simple_shader.h
GPU_select.h
GPU_compositing.h
GPUx_vbo.h
GPUx_draw.h
GPUx_element.h
GPUx_state.h
intern/gpu_codegen.h
intern/gpu_private.h
intern/gpux_element_private.h
)
data_to_c_simple(shaders/gpu_program_smoke_frag.glsl SRC)

View File

@@ -48,6 +48,9 @@ struct GSet;
struct GPUVertPointLink;
struct PBVH;
typedef void (*GPUBufferCopyFunc)(DerivedMesh *dm, float *varray, int *index,
int *mat_orig_to_new, void *user_data);
typedef struct GPUBuffer {
int size; /* in bytes */
void *pointer; /* used with vertex arrays */
@@ -115,6 +118,18 @@ typedef struct GPUDrawObject {
int totedge;
} GPUDrawObject;
/* currently unused */
// #define USE_GPU_POINT_LINK
typedef struct GPUVertPointLink {
#ifdef USE_GPU_POINT_LINK
struct GPUVertPointLink *next;
#endif
/* -1 means uninitialized */
int point_index;
} GPUVertPointLink;
/* used for GLSL materials */
typedef struct GPUAttrib {
int index;
@@ -128,9 +143,20 @@ void GPU_global_buffer_pool_free_unused(void);
GPUBuffer *GPU_buffer_alloc(int size, bool force_vertex_arrays);
void GPU_buffer_free(GPUBuffer *buffer);
GPUDrawObject *GPU_drawobject_new(struct DerivedMesh *dm);
void GPU_drawobject_free(struct DerivedMesh *dm);
/* flag that controls data type to fill buffer with, a modifier will prepare. */
typedef enum {
GPU_BUFFER_VERTEX = 0,
GPU_BUFFER_NORMAL,
GPU_BUFFER_COLOR,
GPU_BUFFER_UV,
GPU_BUFFER_UV_TEXPAINT,
GPU_BUFFER_EDGE,
GPU_BUFFER_UVEDGE,
} GPUBufferType;
/* called before drawing */
void GPU_vertex_setup(struct DerivedMesh *dm);
void GPU_normal_setup(struct DerivedMesh *dm);

View File

@@ -62,6 +62,8 @@ void GPU_extensions_disable(void);
bool GPU_glsl_support(void);
bool GPU_non_power_of_two_support(void);
bool GPU_vertex_buffer_support(void);
bool GPU_vertex_array_object_support(void);
bool GPU_shader4_support(void);
bool GPU_display_list_support(void);
bool GPU_bicubic_bump_support(void);
bool GPU_geometry_shader_support(void);

View File

@@ -34,4 +34,39 @@
#include "glew-mx.h"
#ifdef __APPLE__
/* Vertex Array Objects are part of OpenGL 3.0, or these extensions:
*
* GL_APPLE_vertex_array_object
* ^-- universally supported on Mac, widely supported on Linux (Mesa)
* GL_ARB_vertex_array_object
* ^-- widely supported on Windows & vendors' Linux drivers
*
* The ARB extension differs from the APPLE one in that client
* memory cannot be accessed through a non-zero vertex array object. It also
* differs in that vertex array objects are explicitly not sharable between
* contexts.
* (in other words, the ARB version of VAOs *must* use VBOs for vertex data)
*
* Called and used the exact same way, so alias to unify our VAO code.
*
* Not needed for GL >= 3.0
*/
# undef glIsVertexArray
# define glIsVertexArray glIsVertexArrayAPPLE
# undef glBindVertexArray
# define glBindVertexArray glBindVertexArrayAPPLE
# undef glGenVertexArrays
# define glGenVertexArrays glGenVertexArraysAPPLE
# undef glDeleteVertexArrays
# define glDeleteVertexArrays glDeleteVertexArraysAPPLE
/* TODO: a better workaround? */
#endif /* __APPLE__ */
#endif /* __GPU_GLEW_H__ */

View File

@@ -0,0 +1,44 @@
#ifndef BLENDER_GL_DRAW_PRIMITIVES
#define BLENDER_GL_DRAW_PRIMITIVES
/* Stateless draw functions for lists of primitives.
* Mike Erwin, Dec 2014 */
#include "GPUx_state.h"
#include "GPUx_vbo.h"
#include "GPUx_element.h"
/* pass ElementList = NULL to draw all vertices from VertexBuffer in order
* pass NULL to either state arg to use defaults */
void GPUx_draw_points(const VertexBuffer*, const ElementList*, const PointDrawState*, const CommonDrawState*);
void GPUx_draw_lines(const VertexBuffer*, const ElementList*, const LineDrawState*, const CommonDrawState*);
void GPUx_draw_triangles(const VertexBuffer*, const ElementList*, const PolygonDrawState*, const CommonDrawState*);
/* generic version uses ElementList's primitive type */
void GPUx_draw_primitives(const VertexBuffer*, const ElementList*, const void *primitive_state, const CommonDrawState*);
/* handle normals/shading in various ways */
typedef enum {
NORMAL_DRAW_NONE, /* draw uniform surface (unlit, uncolored) for depth/picking */
NORMAL_DRAW_SMOOTH, /* use vertex normals for smooth appearance */
NORMAL_DRAW_FLAT, /* use poly normals for faceted appearance */
NORMAL_DRAW_LOOP, /* use loop normals for most faithful rendering */
} NormalDrawMode;
typedef struct GPUxBatch {
GLenum prim_type; /* GL_POINTS, GL_LINES, GL_TRIANGLES (must match elem->prim_type) */
int draw_type; /* OB_WIRE, OB_SOLID, OB_MATERIAL */
NormalDrawMode normal_draw_mode;
DrawState state;
VertexBuffer *buff; /* TODO: rename "verts" */
ElementList *elem;
} GPUxBatch;
GPUxBatch *GPUx_batch_create(void);
void GPUx_batch_discard(GPUxBatch*);
unsigned GPUx_batch_size(const GPUxBatch*); /* total, in bytes */
void GPUx_draw_batch(const GPUxBatch*);
#endif /* BLENDER_GL_DRAW_PRIMITIVES */

View File

@@ -0,0 +1,32 @@
#ifndef BLENDER_GL_ELEMENT_LIST
#define BLENDER_GL_ELEMENT_LIST
/* Element lists specify which vertices to use when drawing point,
* line, or triangle primitives. They don't care how the per-vertex
* data (attributes) are laid out, only *which* vertices are used.
* Mike Erwin, Dec 2014 */
#include "GPU_glew.h"
/* ^-- for GLenum (and if you're including this file, you're probably calling OpenGL anyway) */
struct ElementList; /* forward declaration */
typedef struct ElementList ElementList;
ElementList *GPUx_element_list_create(GLenum prim_type, unsigned prim_ct, unsigned max_index);
void GPUx_element_list_discard(ElementList*);
unsigned GPUx_element_list_size(const ElementList*);
void GPUx_set_point_vertex(ElementList*, unsigned prim_idx, unsigned v1);
void GPUx_set_line_vertices(ElementList*, unsigned prim_idx, unsigned v1, unsigned v2);
void GPUx_set_triangle_vertices(ElementList*, unsigned prim_idx, unsigned v1, unsigned v2, unsigned v3);
void GPUx_optimize(ElementList*); /* optionally call this after setting all vertex indices */
/* prime does all the setup (create VBO, send to GPU, etc.) */
void GPUx_element_list_prime(ElementList*);
void GPUx_element_list_use(const ElementList*);
void GPUx_element_list_done_using(const ElementList*);
#endif /* BLENDER_GL_ELEMENT_LIST */

View File

@@ -0,0 +1,63 @@
#ifndef BLENDER_GL_STATE
#define BLENDER_GL_STATE
/* Two goals:
* -- batch draws by state so we don't have to "switch gears" as often
* -- track current draw state internally so we don't have to bother the GL as often
* Mike Erwin, Dec 2014 */
#include <stdbool.h>
typedef struct {
bool blend; /* plus src & dst of glBlendFunc? */
bool depth_test;
bool depth_write;
bool lighting;
bool interpolate; /* affects lines & polygons, not points */
/* TODO: interpolation qualifier per attrib (flat/smooth/noperspective) instead of here */
/* requires GLSL 1.3 (OpenGL 3.0) or EXT_gpu_shader4 */
} CommonDrawState;
typedef struct {
bool smooth; /* implies blend / transparency. Disable depth write! (p179 of AGPUO) */
float size;
} PointDrawState;
typedef struct {
bool smooth; /* implies blend / transparency. Disable depth write! (p179 of AGPUO) */
float width;
int stipple; /* = 0 for don't */
} LineDrawState;
typedef struct {
bool draw_front;
bool draw_back;
int material_id;
int stipple; /* = 0 for don't */
} PolygonDrawState;
#define MATERIAL_NONE -1
typedef struct {
CommonDrawState common;
PointDrawState point;
LineDrawState line;
PolygonDrawState polygon;
} DrawState;
extern const DrawState default_state;
void GPUx_reset_draw_state(void); /* to defaults */
/* ^-- call this before using set_*_state functions below */
/* incrementally update current GL state */
void GPUx_set_common_state(const CommonDrawState*);
void GPUx_set_point_state(const PointDrawState*);
void GPUx_set_line_state(const LineDrawState*);
void GPUx_set_polygon_state(const PolygonDrawState*);
/* update everything regardless of current GL state */
void GPUx_force_state_update(void);
#endif /* BLENDER_GL_STATE */

View File

@@ -0,0 +1,74 @@
#ifndef BLENDER_GL_VERTEX_BUFFER
#define BLENDER_GL_VERTEX_BUFFER
/* vertex buffer support
* Mike Erwin, Nov 2014 */
#include "GPU_glew.h"
/* ^-- for GLenum (and if you're including this file, you're probably calling OpenGL anyway) */
#include <stdbool.h>
//#define GENERIC_ATTRIB
#define TRUST_NO_ONE
//#define PRINT
struct VertexBuffer; /* forward declaration */
typedef struct VertexBuffer VertexBuffer;
typedef enum {
KEEP_FLOAT,
KEEP_INT, /* requires EXT_gpu_shader4 */
NORMALIZE_INT_TO_FLOAT, /* 127 (ubyte) -> 0.5 (and so on for other int types) */
CONVERT_INT_TO_FLOAT /* 127 (any int type) -> 127.0 */
} VertexFetchMode;
VertexBuffer* GPUx_vertex_buffer_create(unsigned attrib_ct, unsigned GPUx_vertex_ct);
void GPUx_vertex_buffer_discard(VertexBuffer*);
unsigned GPUx_vertex_ct(const VertexBuffer*);
unsigned GPUx_vertex_buffer_size(const VertexBuffer*); /* of all vertex attrib data, in bytes */
#ifdef PRINT
void GPUx_attrib_print(const VertexBuffer*, unsigned attrib_num);
#endif /* PRINT */
void GPUx_specify_attrib(VertexBuffer*, unsigned attrib_num,
#ifdef GENERIC_ATTRIB
const char *name, /* use any legal GLSL identifier */
#else
GLenum attrib_array, /* use GL_VERTEX_ARRAY, GL_NORMAL_ARRAY, etc. */
#endif
GLenum comp_type, unsigned comp_ct, VertexFetchMode);
#ifdef GENERIC_ATTRIB
/* binds all our named attributes to internally-used GL indices
* call this before linking the program */
void GPUx_bind_attrib_locations(const VertexBuffer*, GLuint program);
#endif
/* set value of single attribute of single vertex
* incoming data must be of same type & size for this attribute */
void GPUx_set_attrib(VertexBuffer*, unsigned attrib_num, unsigned vertex_num, const void *data);
/* convenience functions for specific type and size
* can add more like this if it's useful */
void GPUx_set_attrib_2f(VertexBuffer*, unsigned attrib_num, unsigned vertex_num, float x, float y);
void GPUx_set_attrib_3f(VertexBuffer*, unsigned attrib_num, unsigned vertex_num, float x, float y, float z);
/* bulk attribute filling routines (all vertices)
* incoming data must be of same type & size for this attribute
* must be tightly packed in memory, no padding */
void GPUx_fill_attrib(VertexBuffer*, unsigned attrib_num, const void *data);
/* this version can have padding between attributes */
void GPUx_fill_attrib_stride(VertexBuffer*, unsigned attrib_num, const void *data, unsigned stride);
/* call before drawing to make this vertex buffer part of current OpenGL state */
void GPUx_vertex_buffer_use(const VertexBuffer*);
/* call after drawing */
void GPUx_vertex_buffer_done_using(const VertexBuffer*);
/* prime does all the setup (create VBOs, send to GPU, etc.)
* call sequence: prime, use {draw} done_using, use {draw} done_using ...
* TODO: wiki page about this */
void GPUx_vertex_buffer_prime(VertexBuffer*);
#endif /* BLENDER_GL_VERTEX_BUFFER */

View File

@@ -69,6 +69,25 @@ typedef enum {
GPU_BUFFER_ELEMENT_STATE = (1 << 5),
} GPUBufferState;
typedef struct {
GLenum gl_buffer_type;
int vector_size;
} GPUBufferTypeSettings;
static int gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type);
const GPUBufferTypeSettings gpu_buffer_type_settings[] = {
{GL_ARRAY_BUFFER_ARB, 3}, /* vertex */
{GL_ARRAY_BUFFER_ARB, 3}, /* normal */
{GL_ARRAY_BUFFER_ARB, 3}, /* mcol */
{GL_ARRAY_BUFFER_ARB, 2}, /* uv */
{GL_ARRAY_BUFFER_ARB, 4}, /* uv for texpaint */
{GL_ELEMENT_ARRAY_BUFFER_ARB, 2}, /* edge */
{GL_ELEMENT_ARRAY_BUFFER_ARB, 4}, /* uv edge */
};
#define MAX_GPU_ATTRIB_DATA 32
#define BUFFER_OFFSET(n) ((GLubyte *)NULL + (n))
@@ -383,186 +402,6 @@ void GPU_buffer_free(GPUBuffer *buffer)
BLI_mutex_unlock(&buffer_mutex);
}
#if 0 /* currently unused */
# define USE_GPU_POINT_LINK
#endif
typedef struct GPUVertPointLink {
#ifdef USE_GPU_POINT_LINK
struct GPUVertPointLink *next;
#endif
/* -1 means uninitialized */
int point_index;
} GPUVertPointLink;
/* add a new point to the list of points related to a particular
* vertex */
#ifdef USE_GPU_POINT_LINK
static void gpu_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index)
{
GPUVertPointLink *lnk;
lnk = &gdo->vert_points[vert_index];
/* if first link is in use, add a new link at the end */
if (lnk->point_index != -1) {
/* get last link */
for (; lnk->next; lnk = lnk->next) ;
/* add a new link from the pool */
lnk = lnk->next = &gdo->vert_points_mem[gdo->vert_points_usage];
gdo->vert_points_usage++;
}
lnk->point_index = point_index;
}
#else
static void gpu_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index)
{
GPUVertPointLink *lnk;
lnk = &gdo->vert_points[vert_index];
if (lnk->point_index == -1) {
lnk->point_index = point_index;
}
}
#endif /* USE_GPU_POINT_LINK */
/* update the vert_points and triangle_to_mface fields with a new
* triangle */
static void gpu_drawobject_add_triangle(GPUDrawObject *gdo,
int base_point_index,
int face_index,
int v1, int v2, int v3)
{
int i, v[3] = {v1, v2, v3};
for (i = 0; i < 3; i++)
gpu_drawobject_add_vert_point(gdo, v[i], base_point_index + i);
gdo->triangle_to_mface[base_point_index / 3] = face_index;
}
/* for each vertex, build a list of points related to it; these lists
* are stored in an array sized to the number of vertices */
static void gpu_drawobject_init_vert_points(GPUDrawObject *gdo, MFace *f, int totface, int totmat)
{
GPUBufferMaterial *mat;
int i, *mat_orig_to_new;
mat_orig_to_new = MEM_callocN(sizeof(*mat_orig_to_new) * totmat,
"GPUDrawObject.mat_orig_to_new");
/* allocate the array and space for links */
gdo->vert_points = MEM_mallocN(sizeof(GPUVertPointLink) * gdo->totvert,
"GPUDrawObject.vert_points");
#ifdef USE_GPU_POINT_LINK
gdo->vert_points_mem = MEM_callocN(sizeof(GPUVertPointLink) * gdo->tot_triangle_point,
"GPUDrawObject.vert_points_mem");
gdo->vert_points_usage = 0;
#endif
/* build a map from the original material indices to the new
* GPUBufferMaterial indices */
for (i = 0; i < gdo->totmaterial; i++)
mat_orig_to_new[gdo->materials[i].mat_nr] = i;
/* -1 indicates the link is not yet used */
for (i = 0; i < gdo->totvert; i++) {
#ifdef USE_GPU_POINT_LINK
gdo->vert_points[i].link = NULL;
#endif
gdo->vert_points[i].point_index = -1;
}
for (i = 0; i < totface; i++, f++) {
mat = &gdo->materials[mat_orig_to_new[f->mat_nr]];
/* add triangle */
gpu_drawobject_add_triangle(gdo, mat->start + mat->totpoint,
i, f->v1, f->v2, f->v3);
mat->totpoint += 3;
/* add second triangle for quads */
if (f->v4) {
gpu_drawobject_add_triangle(gdo, mat->start + mat->totpoint,
i, f->v3, f->v4, f->v1);
mat->totpoint += 3;
}
}
/* map any unused vertices to loose points */
for (i = 0; i < gdo->totvert; i++) {
if (gdo->vert_points[i].point_index == -1) {
gdo->vert_points[i].point_index = gdo->tot_triangle_point + gdo->tot_loose_point;
gdo->tot_loose_point++;
}
}
MEM_freeN(mat_orig_to_new);
}
/* see GPUDrawObject's structure definition for a description of the
* data being initialized here */
GPUDrawObject *GPU_drawobject_new(DerivedMesh *dm)
{
GPUDrawObject *gdo;
MFace *mface;
int totmat = dm->totmat;
int *points_per_mat;
int i, curmat, curpoint, totface;
/* object contains at least one material (default included) so zero means uninitialized dm */
BLI_assert(totmat != 0);
mface = dm->getTessFaceArray(dm);
totface = dm->getNumTessFaces(dm);
/* get the number of points used by each material, treating
* each quad as two triangles */
points_per_mat = MEM_callocN(sizeof(*points_per_mat) * totmat, "GPU_drawobject_new.mat_orig_to_new");
for (i = 0; i < totface; i++)
points_per_mat[mface[i].mat_nr] += mface[i].v4 ? 6 : 3;
/* create the GPUDrawObject */
gdo = MEM_callocN(sizeof(GPUDrawObject), "GPUDrawObject");
gdo->totvert = dm->getNumVerts(dm);
gdo->totedge = dm->getNumEdges(dm);
/* count the number of materials used by this DerivedMesh */
for (i = 0; i < totmat; i++) {
if (points_per_mat[i] > 0)
gdo->totmaterial++;
}
/* allocate an array of materials used by this DerivedMesh */
gdo->materials = MEM_mallocN(sizeof(GPUBufferMaterial) * gdo->totmaterial,
"GPUDrawObject.materials");
/* initialize the materials array */
for (i = 0, curmat = 0, curpoint = 0; i < totmat; i++) {
if (points_per_mat[i] > 0) {
gdo->materials[curmat].start = curpoint;
gdo->materials[curmat].totpoint = 0;
gdo->materials[curmat].mat_nr = i;
curpoint += points_per_mat[i];
curmat++;
}
}
/* store total number of points used for triangles */
gdo->tot_triangle_point = curpoint;
gdo->triangle_to_mface = MEM_mallocN(sizeof(int) * (gdo->tot_triangle_point / 3),
"GPUDrawObject.triangle_to_mface");
gpu_drawobject_init_vert_points(gdo, mface, totface, totmat);
MEM_freeN(points_per_mat);
return gdo;
}
void GPU_drawobject_free(DerivedMesh *dm)
{
@@ -572,8 +411,10 @@ void GPU_drawobject_free(DerivedMesh *dm)
return;
MEM_freeN(gdo->materials);
MEM_freeN(gdo->triangle_to_mface);
MEM_freeN(gdo->vert_points);
if (gdo->triangle_to_mface)
MEM_freeN(gdo->triangle_to_mface);
if (gdo->vert_points)
MEM_freeN(gdo->vert_points);
#ifdef USE_GPU_POINT_LINK
MEM_freeN(gdo->vert_points_mem);
#endif
@@ -605,12 +446,8 @@ static GPUBuffer *gpu_try_realloc(GPUBufferPool *pool, GPUBuffer *buffer, int si
return buffer;
}
typedef void (*GPUBufferCopyFunc)(DerivedMesh *dm, float *varray, int *index,
int *mat_orig_to_new, void *user_data);
static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
int vector_size, int size, GLenum target,
void *user, GPUBufferCopyFunc copy_f)
int type, void *user)
{
GPUBufferPool *pool;
GPUBuffer *buffer;
@@ -618,6 +455,10 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
int *mat_orig_to_new;
int *cur_index_per_mat;
int i;
const GPUBufferTypeSettings *ts = &gpu_buffer_type_settings[type];
GLenum target = ts->gl_buffer_type;
int vector_size = ts->vector_size;
int size = gpu_buffer_size_from_type(dm, type);
bool use_VBOs = (GLEW_ARB_vertex_buffer_object) && !(U.gameflags & USER_DISABLE_VBO);
GLboolean uploaded;
@@ -674,7 +515,8 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
uploaded = GL_FALSE;
/* attempt to upload the data to the VBO */
while (uploaded == GL_FALSE) {
(*copy_f)(dm, varray, cur_index_per_mat, mat_orig_to_new, user);
if (dm->copy_gpu_data)
dm->copy_gpu_data(dm, type, varray, cur_index_per_mat, mat_orig_to_new, user);
/* glUnmapBuffer returns GL_FALSE if
* the data store is corrupted; retry
* in that case */
@@ -691,7 +533,8 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
if (buffer) {
varray = buffer->pointer;
(*copy_f)(dm, varray, cur_index_per_mat, mat_orig_to_new, user);
if (dm->copy_gpu_data)
dm->copy_gpu_data(dm, type, varray, cur_index_per_mat, mat_orig_to_new, user);
}
}
@@ -703,315 +546,7 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
return buffer;
}
static void GPU_buffer_copy_vertex(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
{
MVert *mvert;
MFace *f;
int i, j, start, totface;
mvert = dm->getVertArray(dm);
f = dm->getTessFaceArray(dm);
totface = dm->getNumTessFaces(dm);
for (i = 0; i < totface; i++, f++) {
start = index[mat_orig_to_new[f->mat_nr]];
/* v1 v2 v3 */
copy_v3_v3(&varray[start], mvert[f->v1].co);
copy_v3_v3(&varray[start + 3], mvert[f->v2].co);
copy_v3_v3(&varray[start + 6], mvert[f->v3].co);
index[mat_orig_to_new[f->mat_nr]] += 9;
if (f->v4) {
/* v3 v4 v1 */
copy_v3_v3(&varray[start + 9], mvert[f->v3].co);
copy_v3_v3(&varray[start + 12], mvert[f->v4].co);
copy_v3_v3(&varray[start + 15], mvert[f->v1].co);
index[mat_orig_to_new[f->mat_nr]] += 9;
}
}
/* copy loose points */
j = dm->drawObject->tot_triangle_point * 3;
for (i = 0; i < dm->drawObject->totvert; i++) {
if (dm->drawObject->vert_points[i].point_index >= dm->drawObject->tot_triangle_point) {
copy_v3_v3(&varray[j], mvert[i].co);
j += 3;
}
}
}
static void GPU_buffer_copy_normal(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
{
int i, totface;
int start;
float f_no[3];
const float *nors = dm->getTessFaceDataArray(dm, CD_NORMAL);
short (*tlnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
MVert *mvert = dm->getVertArray(dm);
MFace *f = dm->getTessFaceArray(dm);
totface = dm->getNumTessFaces(dm);
for (i = 0; i < totface; i++, f++) {
const int smoothnormal = (f->flag & ME_SMOOTH);
start = index[mat_orig_to_new[f->mat_nr]];
index[mat_orig_to_new[f->mat_nr]] += f->v4 ? 18 : 9;
if (tlnors) {
short (*tlnor)[3] = tlnors[i];
/* Copy loop normals */
normal_short_to_float_v3(&varray[start], tlnor[0]);
normal_short_to_float_v3(&varray[start + 3], tlnor[1]);
normal_short_to_float_v3(&varray[start + 6], tlnor[2]);
if (f->v4) {
normal_short_to_float_v3(&varray[start + 9], tlnor[2]);
normal_short_to_float_v3(&varray[start + 12], tlnor[3]);
normal_short_to_float_v3(&varray[start + 15], tlnor[0]);
}
}
else if (smoothnormal) {
/* copy vertex normal */
normal_short_to_float_v3(&varray[start], mvert[f->v1].no);
normal_short_to_float_v3(&varray[start + 3], mvert[f->v2].no);
normal_short_to_float_v3(&varray[start + 6], mvert[f->v3].no);
if (f->v4) {
normal_short_to_float_v3(&varray[start + 9], mvert[f->v3].no);
normal_short_to_float_v3(&varray[start + 12], mvert[f->v4].no);
normal_short_to_float_v3(&varray[start + 15], mvert[f->v1].no);
}
}
else if (nors) {
/* copy cached face normal */
copy_v3_v3(&varray[start], &nors[i * 3]);
copy_v3_v3(&varray[start + 3], &nors[i * 3]);
copy_v3_v3(&varray[start + 6], &nors[i * 3]);
if (f->v4) {
copy_v3_v3(&varray[start + 9], &nors[i * 3]);
copy_v3_v3(&varray[start + 12], &nors[i * 3]);
copy_v3_v3(&varray[start + 15], &nors[i * 3]);
}
}
else {
/* calculate face normal */
if (f->v4)
normal_quad_v3(f_no, mvert[f->v1].co, mvert[f->v2].co, mvert[f->v3].co, mvert[f->v4].co);
else
normal_tri_v3(f_no, mvert[f->v1].co, mvert[f->v2].co, mvert[f->v3].co);
copy_v3_v3(&varray[start], f_no);
copy_v3_v3(&varray[start + 3], f_no);
copy_v3_v3(&varray[start + 6], f_no);
if (f->v4) {
copy_v3_v3(&varray[start + 9], f_no);
copy_v3_v3(&varray[start + 12], f_no);
copy_v3_v3(&varray[start + 15], f_no);
}
}
}
}
static void GPU_buffer_copy_uv(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
{
int start;
int i, totface;
MTFace *mtface;
MFace *f;
if (!(mtface = DM_get_tessface_data_layer(dm, CD_MTFACE)))
return;
f = dm->getTessFaceArray(dm);
totface = dm->getNumTessFaces(dm);
for (i = 0; i < totface; i++, f++) {
start = index[mat_orig_to_new[f->mat_nr]];
/* v1 v2 v3 */
copy_v2_v2(&varray[start], mtface[i].uv[0]);
copy_v2_v2(&varray[start + 2], mtface[i].uv[1]);
copy_v2_v2(&varray[start + 4], mtface[i].uv[2]);
index[mat_orig_to_new[f->mat_nr]] += 6;
if (f->v4) {
/* v3 v4 v1 */
copy_v2_v2(&varray[start + 6], mtface[i].uv[2]);
copy_v2_v2(&varray[start + 8], mtface[i].uv[3]);
copy_v2_v2(&varray[start + 10], mtface[i].uv[0]);
index[mat_orig_to_new[f->mat_nr]] += 6;
}
}
}
static void GPU_buffer_copy_uv_texpaint(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
{
int start;
int i, totface;
int totmaterial = dm->totmat;
MTFace **mtface_base;
MTFace *stencil_base;
int stencil;
MFace *mf;
/* should have been checked for before, reassert */
BLI_assert(DM_get_tessface_data_layer(dm, CD_MTFACE));
mf = dm->getTessFaceArray(dm);
mtface_base = MEM_mallocN(totmaterial * sizeof(*mtface_base), "texslots");
for (i = 0; i < totmaterial; i++) {
mtface_base[i] = DM_paint_uvlayer_active_get(dm, i);
}
stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE);
stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil);
totface = dm->getNumTessFaces(dm);
for (i = 0; i < totface; i++, mf++) {
int mat_i = mf->mat_nr;
start = index[mat_orig_to_new[mat_i]];
/* v1 v2 v3 */
copy_v2_v2(&varray[start], mtface_base[mat_i][i].uv[0]);
copy_v2_v2(&varray[start + 2], stencil_base[i].uv[0]);
copy_v2_v2(&varray[start + 4], mtface_base[mat_i][i].uv[1]);
copy_v2_v2(&varray[start + 6], stencil_base[i].uv[1]);
copy_v2_v2(&varray[start + 8], mtface_base[mat_i][i].uv[2]);
copy_v2_v2(&varray[start + 10], stencil_base[i].uv[2]);
index[mat_orig_to_new[mat_i]] += 12;
if (mf->v4) {
/* v3 v4 v1 */
copy_v2_v2(&varray[start + 12], mtface_base[mat_i][i].uv[2]);
copy_v2_v2(&varray[start + 14], stencil_base[i].uv[2]);
copy_v2_v2(&varray[start + 16], mtface_base[mat_i][i].uv[3]);
copy_v2_v2(&varray[start + 18], stencil_base[i].uv[3]);
copy_v2_v2(&varray[start + 20], mtface_base[mat_i][i].uv[0]);
copy_v2_v2(&varray[start + 22], stencil_base[i].uv[0]);
index[mat_orig_to_new[mat_i]] += 12;
}
}
MEM_freeN(mtface_base);
}
static void copy_mcol_uc3(unsigned char *v, unsigned char *col)
{
v[0] = col[3];
v[1] = col[2];
v[2] = col[1];
}
/* treat varray_ as an array of MCol, four MCol's per face */
static void GPU_buffer_copy_mcol(DerivedMesh *dm, float *varray_, int *index, int *mat_orig_to_new, void *user)
{
int i, totface;
unsigned char *varray = (unsigned char *)varray_;
unsigned char *mcol = (unsigned char *)user;
MFace *f = dm->getTessFaceArray(dm);
totface = dm->getNumTessFaces(dm);
for (i = 0; i < totface; i++, f++) {
int start = index[mat_orig_to_new[f->mat_nr]];
/* v1 v2 v3 */
copy_mcol_uc3(&varray[start], &mcol[i * 16]);
copy_mcol_uc3(&varray[start + 3], &mcol[i * 16 + 4]);
copy_mcol_uc3(&varray[start + 6], &mcol[i * 16 + 8]);
index[mat_orig_to_new[f->mat_nr]] += 9;
if (f->v4) {
/* v3 v4 v1 */
copy_mcol_uc3(&varray[start + 9], &mcol[i * 16 + 8]);
copy_mcol_uc3(&varray[start + 12], &mcol[i * 16 + 12]);
copy_mcol_uc3(&varray[start + 15], &mcol[i * 16]);
index[mat_orig_to_new[f->mat_nr]] += 9;
}
}
}
static void GPU_buffer_copy_edge(DerivedMesh *dm, float *varray_, int *UNUSED(index), int *UNUSED(mat_orig_to_new), void *UNUSED(user))
{
MEdge *medge;
unsigned int *varray = (unsigned int *)varray_;
int i, totedge;
medge = dm->getEdgeArray(dm);
totedge = dm->getNumEdges(dm);
for (i = 0; i < totedge; i++, medge++) {
varray[i * 2] = dm->drawObject->vert_points[medge->v1].point_index;
varray[i * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
}
}
static void GPU_buffer_copy_uvedge(DerivedMesh *dm, float *varray, int *UNUSED(index), int *UNUSED(mat_orig_to_new), void *UNUSED(user))
{
MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
int i, j = 0;
if (!tf)
return;
for (i = 0; i < dm->numTessFaceData; i++, tf++) {
MFace mf;
dm->getTessFace(dm, i, &mf);
copy_v2_v2(&varray[j], tf->uv[0]);
copy_v2_v2(&varray[j + 2], tf->uv[1]);
copy_v2_v2(&varray[j + 4], tf->uv[1]);
copy_v2_v2(&varray[j + 6], tf->uv[2]);
if (!mf.v4) {
copy_v2_v2(&varray[j + 8], tf->uv[2]);
copy_v2_v2(&varray[j + 10], tf->uv[0]);
j += 12;
}
else {
copy_v2_v2(&varray[j + 8], tf->uv[2]);
copy_v2_v2(&varray[j + 10], tf->uv[3]);
copy_v2_v2(&varray[j + 12], tf->uv[3]);
copy_v2_v2(&varray[j + 14], tf->uv[0]);
j += 16;
}
}
}
typedef enum {
GPU_BUFFER_VERTEX = 0,
GPU_BUFFER_NORMAL,
GPU_BUFFER_COLOR,
GPU_BUFFER_UV,
GPU_BUFFER_UV_TEXPAINT,
GPU_BUFFER_EDGE,
GPU_BUFFER_UVEDGE,
} GPUBufferType;
typedef struct {
GPUBufferCopyFunc copy;
GLenum gl_buffer_type;
int vector_size;
} GPUBufferTypeSettings;
const GPUBufferTypeSettings gpu_buffer_type_settings[] = {
{GPU_buffer_copy_vertex, GL_ARRAY_BUFFER_ARB, 3},
{GPU_buffer_copy_normal, GL_ARRAY_BUFFER_ARB, 3},
{GPU_buffer_copy_mcol, GL_ARRAY_BUFFER_ARB, 3},
{GPU_buffer_copy_uv, GL_ARRAY_BUFFER_ARB, 2},
{GPU_buffer_copy_uv_texpaint, GL_ARRAY_BUFFER_ARB, 4},
{GPU_buffer_copy_edge, GL_ELEMENT_ARRAY_BUFFER_ARB, 2},
{GPU_buffer_copy_uvedge, GL_ELEMENT_ARRAY_BUFFER_ARB, 4}
};
/* get the GPUDrawObject buffer associated with a type */
static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBufferType type)
@@ -1067,12 +602,9 @@ static int gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type)
/* call gpu_buffer_setup with settings for a particular type of buffer */
static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type)
{
const GPUBufferTypeSettings *ts;
void *user_data = NULL;
GPUBuffer *buf;
ts = &gpu_buffer_type_settings[type];
/* special handling for MCol and UV buffers */
if (type == GPU_BUFFER_COLOR) {
if (!(user_data = DM_get_tessface_data_layer(dm, dm->drawObject->colType)))
@@ -1083,9 +615,7 @@ static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type)
return NULL;
}
buf = gpu_buffer_setup(dm, dm->drawObject, ts->vector_size,
gpu_buffer_size_from_type(dm, type),
ts->gl_buffer_type, user_data, ts->copy);
buf = gpu_buffer_setup(dm, dm->drawObject, type, user_data);
return buf;
}
@@ -1096,9 +626,13 @@ static GPUBuffer *gpu_buffer_setup_common(DerivedMesh *dm, GPUBufferType type)
{
GPUBuffer **buf;
if (!dm->drawObject)
dm->drawObject = GPU_drawobject_new(dm);
if (!dm->drawObject) {
if (dm->gpuObjectNew)
dm->drawObject = dm->gpuObjectNew(dm);
else
return NULL;
}
buf = gpu_drawobject_buffer_from_type(dm->drawObject, type);
if (!(*buf))
*buf = gpu_buffer_setup_type(dm, type);
@@ -1188,7 +722,7 @@ void GPU_color_setup(DerivedMesh *dm, int colType)
if (!dm->drawObject) {
/* XXX Not really nice, but we need a valid gpu draw object to set the colType...
* Else we would have to add a new param to gpu_buffer_setup_common. */
dm->drawObject = GPU_drawobject_new(dm);
dm->drawObject = dm->gpuObjectNew(dm);
dm->dirty &= ~DM_DIRTY_MCOL_UPDATE_DRAW;
dm->drawObject->colType = colType;
}

View File

@@ -303,6 +303,22 @@ bool GPU_vertex_buffer_support(void)
return GLEW_ARB_vertex_buffer_object || GLEW_VERSION_1_5;
}
bool GPU_vertex_array_object_support(void)
{
return GLEW_VERSION_3_0 || GLEW_ARB_vertex_array_object || GLEW_APPLE_vertex_array_object;
}
bool GPU_shader4_support(void)
{
/* includes a number of GLSL enhancements:
* - full integer support
* - interpolation qualifiers (flat, smooth, noperspective)
* - gl_VertexID, gl_PrimitiveID
* - custom fragment shader outputs, for MRT
*/
return GLEW_VERSION_3_0 || GLEW_EXT_gpu_shader4;
}
bool GPU_display_list_support(void)
{
return !GG.dlistsdisabled;

View File

@@ -0,0 +1,95 @@
#include "gpux_buffer_id.h"
#include "BLI_utildefines.h"
#include "BLI_threads.h"
//#define ORPHAN_DEBUG
#ifdef ORPHAN_DEBUG
#include <stdio.h>
#endif
#define ORPHANED_BUFFER_MAX 48
static GLuint orphaned_buffer_ids[ORPHANED_BUFFER_MAX];
static unsigned orphaned_buffer_ct = 0;
#define ORPHANED_VAO_MAX 16
static GLuint orphaned_vao_ids[ORPHANED_VAO_MAX];
static unsigned orphaned_vao_ct = 0;
static ThreadMutex orphan_mutex = BLI_MUTEX_INITIALIZER;
GLuint buffer_id_alloc()
{
GLuint new_buffer_id;
BLI_assert(BLI_thread_is_main());
/* delete orphaned IDs */
BLI_mutex_lock(&orphan_mutex);
if (orphaned_buffer_ct) {
#ifdef ORPHAN_DEBUG
printf("deleting %d orphaned VBO%s\n", orphaned_buffer_ct, orphaned_buffer_ct == 1 ? "" : "s");
#endif
glDeleteBuffers(orphaned_buffer_ct, orphaned_buffer_ids);
orphaned_buffer_ct = 0;
}
BLI_mutex_unlock(&orphan_mutex);
glGenBuffers(1, &new_buffer_id);
return new_buffer_id;
}
void buffer_id_free(GLuint buffer_id)
{
if (BLI_thread_is_main()) {
glDeleteBuffers(1, &buffer_id);
}
else {
/* add this ID to the orphaned list */
BLI_mutex_lock(&orphan_mutex);
BLI_assert(orphaned_buffer_ct < ORPHANED_BUFFER_MAX); /* increase MAX if needed */
#ifdef ORPHAN_DEBUG
printf("orphaning VBO %d\n", buffer_id);
#endif
orphaned_buffer_ids[orphaned_buffer_ct++] = buffer_id;
BLI_mutex_unlock(&orphan_mutex);
}
}
GLuint vao_id_alloc()
{
GLuint new_vao_id;
BLI_assert(BLI_thread_is_main());
/* delete orphaned IDs */
BLI_mutex_lock(&orphan_mutex);
if (orphaned_vao_ct) {
#ifdef ORPHAN_DEBUG
printf("deleting %d orphaned VAO%s\n", orphaned_vao_ct, orphaned_vao_ct == 1 ? "" : "s");
#endif
glDeleteVertexArrays(orphaned_vao_ct, orphaned_vao_ids);
orphaned_vao_ct = 0;
}
BLI_mutex_unlock(&orphan_mutex);
glGenVertexArrays(1, &new_vao_id);
return new_vao_id;
}
void vao_id_free(GLuint vao_id)
{
if (BLI_thread_is_main()) {
glDeleteVertexArrays(1, &vao_id);
}
else {
/* add this ID to the orphaned list */
BLI_mutex_lock(&orphan_mutex);
BLI_assert(orphaned_vao_ct < ORPHANED_VAO_MAX); /* increase MAX if needed */
#ifdef ORPHAN_DEBUG
printf("orphaning VAO %d\n", vao_id);
#endif
orphaned_vao_ids[orphaned_vao_ct++] = vao_id;
BLI_mutex_unlock(&orphan_mutex);
}
}

View File

@@ -0,0 +1,19 @@
#ifndef BLENDER_GL_BUFFER_ID
#define BLENDER_GL_BUFFER_ID
/* 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
* private for now since GPUx uses this internally
* Mike Erwin, April 2015 */
#include "GPU_glew.h"
GLuint buffer_id_alloc(void);
void buffer_id_free(GLuint buffer_id);
GLuint vao_id_alloc(void);
void vao_id_free(GLuint vao_id);
#endif /* BLENDER_GL_BUFFER_ID */

View File

@@ -0,0 +1,213 @@
#include "GPUx_draw.h"
#include "gpux_element_private.h"
#include "MEM_guardedalloc.h"
#ifdef TRUST_NO_ONE
#include "BLI_utildefines.h"
#endif /* TRUST_NO_ONE */
#define REALLY_DRAW
/* generally useful utility function */
static unsigned chop_to_multiple(unsigned x, unsigned m)
{
return x - x % m;
}
void GPUx_draw_points(const VertexBuffer *vbo, const ElementList *el, const PointDrawState *point_state, const CommonDrawState *common_state)
{
GPUx_set_common_state(common_state);
GPUx_set_point_state(point_state);
#ifdef TRUST_NO_ONE
if (el) {
BLI_assert(el->prim_type == GL_POINTS);
BLI_assert(max_index(el) < GPUx_vertex_ct(vbo));
}
#endif /* TRUST_NO_ONE */
#ifdef REALLY_DRAW
GPUx_vertex_buffer_use(vbo);
if (el) {
GPUx_element_list_use(el);
glDrawRangeElements(GL_POINTS, min_index(el), max_index(el), el->prim_ct, el->index_type, index_ptr(el));
GPUx_element_list_done_using(el);
}
else
glDrawArrays(GL_POINTS, 0, GPUx_vertex_ct(vbo));
GPUx_vertex_buffer_done_using(vbo);
#endif /* REALLY_DRAW */
}
void GPUx_draw_lines(const VertexBuffer *vbo, const ElementList *el, const LineDrawState *line_state, const CommonDrawState *common_state)
{
GPUx_set_common_state(common_state);
GPUx_set_line_state(line_state);
#ifdef TRUST_NO_ONE
if (el) {
BLI_assert(el->prim_type == GL_LINES);
BLI_assert(max_index(el) < GPUx_vertex_ct(vbo));
}
#endif /* TRUST_NO_ONE */
#ifdef REALLY_DRAW
GPUx_vertex_buffer_use(vbo);
if (el) {
GPUx_element_list_use(el);
glDrawRangeElements(GL_LINES, min_index(el), max_index(el), el->prim_ct * 2, el->index_type, index_ptr(el));
GPUx_element_list_done_using(el);
}
else
glDrawArrays(GL_LINES, 0, chop_to_multiple(GPUx_vertex_ct(vbo), 2));
GPUx_vertex_buffer_done_using(vbo);
#endif /* REALLY_DRAW */
}
void GPUx_draw_triangles(const VertexBuffer *vbo, const ElementList *el, const PolygonDrawState *polygon_state, const CommonDrawState *common_state)
{
GPUx_set_common_state(common_state);
GPUx_set_polygon_state(polygon_state);
#ifdef TRUST_NO_ONE
if (el) {
BLI_assert(el->prim_type == GL_TRIANGLES);
BLI_assert(max_index(el) < GPUx_vertex_ct(vbo));
}
#endif /* TRUST_NO_ONE */
#ifdef REALLY_DRAW
GPUx_vertex_buffer_use(vbo);
if (el) {
GPUx_element_list_use(el);
glDrawRangeElements(GL_TRIANGLES, min_index(el), max_index(el), el->prim_ct * 3, el->index_type, index_ptr(el));
GPUx_element_list_done_using(el);
}
else
glDrawArrays(GL_TRIANGLES, 0, chop_to_multiple(GPUx_vertex_ct(vbo), 3));
GPUx_vertex_buffer_done_using(vbo);
#endif /* REALLY_DRAW */
}
void GPUx_draw_primitives(const VertexBuffer *vbo, const ElementList *el, const void *primitive_state, const CommonDrawState *common_state)
{
int vert_per_prim = 0;
#ifdef TRUST_NO_ONE
BLI_assert(max_index(el) < GPUx_vertex_ct(vbo));
#endif /* TRUST_NO_ONE */
switch (el->prim_type) {
case GL_POINTS:
GPUx_set_point_state((const PointDrawState*)primitive_state);
vert_per_prim = 1;
break;
case GL_LINES:
GPUx_set_line_state((const LineDrawState*)primitive_state);
vert_per_prim = 2;
break;
case GL_TRIANGLES:
GPUx_set_polygon_state((const PolygonDrawState*)primitive_state);
vert_per_prim = 3;
break;
default:
#ifdef TRUST_NO_ONE
BLI_assert(false);
#else
return;
#endif /* TRUST_NO_ONE */
}
GPUx_set_common_state(common_state);
#ifdef REALLY_DRAW
GPUx_vertex_buffer_use(vbo);
GPUx_element_list_use(el);
glDrawRangeElements(el->prim_type, min_index(el), max_index(el), el->prim_ct * vert_per_prim, el->index_type, index_ptr(el));
GPUx_element_list_done_using(el);
GPUx_vertex_buffer_done_using(vbo);
#endif /* REALLY_DRAW */
}
GPUxBatch *GPUx_batch_create()
{
GPUxBatch *batch = MEM_callocN(sizeof(GPUxBatch), "GPUxBatch");
batch->prim_type = GL_NONE;
batch->state = default_state;
return batch;
}
void GPUx_batch_discard(GPUxBatch *batch)
{
GPUx_vertex_buffer_discard(batch->buff);
if (batch->elem)
GPUx_element_list_discard(batch->elem);
MEM_freeN(batch);
}
unsigned GPUx_batch_size(const GPUxBatch *batch)
{
unsigned sz = GPUx_vertex_buffer_size(batch->buff);
if (batch->elem)
sz += GPUx_element_list_size(batch->elem);
return sz;
}
void GPUx_draw_batch(const GPUxBatch *batch)
{
int vert_per_prim = 0;
#ifdef TRUST_NO_ONE
if (batch->elem) {
BLI_assert(batch->elem->prim_type == batch->prim_type);
BLI_assert(max_index(batch->elem) < GPUx_vertex_ct(batch->buff));
}
#endif /* TRUST_NO_ONE */
switch (batch->prim_type) {
case GL_POINTS:
GPUx_set_point_state(&batch->state.point);
vert_per_prim = 1;
break;
case GL_LINES:
GPUx_set_line_state(&batch->state.line);
vert_per_prim = 2;
break;
case GL_TRIANGLES:
GPUx_set_polygon_state(&batch->state.polygon);
vert_per_prim = 3;
break;
default:
#ifdef TRUST_NO_ONE
BLI_assert(false);
#else
return;
#endif /* TRUST_NO_ONE */
}
GPUx_set_common_state(&batch->state.common);
#ifdef REALLY_DRAW
GPUx_vertex_buffer_use(batch->buff);
if (batch->elem) {
GPUx_element_list_use(batch->elem);
glDrawRangeElements(batch->prim_type, min_index(batch->elem), max_index(batch->elem),
batch->elem->prim_ct * vert_per_prim, batch->elem->index_type, index_ptr(batch->elem));
GPUx_element_list_done_using(batch->elem);
}
else
glDrawArrays(batch->prim_type, 0, chop_to_multiple(GPUx_vertex_ct(batch->buff), vert_per_prim));
GPUx_vertex_buffer_done_using(batch->buff);
#endif /* REALLY_DRAW */
}

View File

@@ -0,0 +1,290 @@
#include "gpux_element_private.h"
#include "gpux_buffer_id.h"
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
#ifdef USE_ELEM_VBO
/* keep index data in main mem or VRAM (not both) */
#define KEEP_SINGLE_COPY
#endif
/* private functions */
#ifdef TRACK_INDEX_RANGE
static void track_index_range(ElementList *el, unsigned v)
{
if (v < el->min_observed_index)
el->min_observed_index = v;
if (v > el->max_observed_index) /* would say "else if" but the first time... */
el->max_observed_index = v;
}
#endif /* TRACK_INDEX_RANGE */
unsigned min_index(const ElementList *el)
{
#ifdef TRACK_INDEX_RANGE
return el->min_observed_index;
#else
return 0;
#endif /* TRACK_INDEX_RANGE */
}
unsigned max_index(const ElementList *el)
{
#ifdef TRACK_INDEX_RANGE
return el->max_observed_index;
#else
return el->max_allowed_index;
#endif /* TRACK_INDEX_RANGE */
}
const void *index_ptr(const ElementList *el)
{
#ifdef USE_ELEM_VBO
if (el->vbo_id) /* primed, data lives in buffer object */
return (const void*)0;
else /* data lives in client memory */
return el->indices;
#else
return el->indices;
#endif /* USE_ELEM_VBO */
}
/* public functions */
ElementList *GPUx_element_list_create(GLenum prim_type, unsigned prim_ct, unsigned max_index)
{
ElementList *el;
#ifdef TRUST_NO_ONE
BLI_assert(prim_type == GL_POINTS || prim_type == GL_LINES || prim_type == GL_TRIANGLES);
#endif /* TRUST_NO_ONE */
el = MEM_callocN(sizeof(ElementList), "ElementList");
el->prim_type = prim_type;
el->prim_ct = prim_ct;
el->max_allowed_index = max_index;
if (max_index <= 255)
el->index_type = GL_UNSIGNED_BYTE;
else if (max_index <= 65535)
el->index_type = GL_UNSIGNED_SHORT;
else
el->index_type = GL_UNSIGNED_INT;
#ifdef TRACK_INDEX_RANGE
el->min_observed_index = max_index + 1; /* any valid index will be < this */
el->max_observed_index = 0;
#endif /* TRACK_INDEX_RANGE */
el->indices = MEM_callocN(GPUx_element_list_size(el), "ElementList.indices");
return el;
}
void GPUx_element_list_discard(ElementList *el)
{
#ifdef USE_ELEM_VBO
if (el->vbo_id)
buffer_id_free(el->vbo_id);
#endif /* USE_ELEM_VBO */
if (el->indices)
MEM_freeN(el->indices);
MEM_freeN(el);
}
unsigned GPUx_element_list_size(const ElementList *el)
{
unsigned prim_vertex_ct = 0, index_size = 0;
if (el->prim_type == GL_POINTS)
prim_vertex_ct = 1;
else if (el->prim_type == GL_LINES)
prim_vertex_ct = 2;
else if (el->prim_type == GL_TRIANGLES)
prim_vertex_ct = 3;
if (el->index_type == GL_UNSIGNED_BYTE)
index_size = sizeof(GLubyte);
else if (el->index_type == GL_UNSIGNED_SHORT)
index_size = sizeof(GLushort);
else if (el->index_type == GL_UNSIGNED_INT)
index_size = sizeof(GLuint);
return prim_vertex_ct * el->prim_ct * index_size;
}
void GPUx_set_point_vertex(ElementList *el, unsigned prim_idx, unsigned v1)
{
const unsigned offset = prim_idx;
#ifdef TRUST_NO_ONE
BLI_assert(el->prim_type == GL_POINTS);
BLI_assert(prim_idx < el->prim_ct); /* prim out of range */
BLI_assert(v1 <= el->max_allowed_index); /* index out of range */
#endif /* TRUST_NO_ONE */
#ifdef TRACK_INDEX_RANGE
track_index_range(el, v1);
#endif /* TRACK_INDEX_RANGE */
switch (el->index_type) {
case GL_UNSIGNED_BYTE:
{
GLubyte *indices = el->indices;
indices[offset] = v1;
break;
}
case GL_UNSIGNED_SHORT:
{
GLushort *indices = el->indices;
indices[offset] = v1;
break;
}
case GL_UNSIGNED_INT:
{
GLuint *indices = el->indices;
indices[offset] = v1;
break;
}
}
}
void GPUx_set_line_vertices(ElementList *el, unsigned prim_idx, unsigned v1, unsigned v2)
{
const unsigned offset = prim_idx * 2;
#ifdef TRUST_NO_ONE
BLI_assert(el->prim_type == GL_LINES);
BLI_assert(prim_idx < el->prim_ct); /* prim out of range */
BLI_assert(v1 <= el->max_allowed_index && v2 <= el->max_allowed_index); /* index out of range */
BLI_assert(v1 != v2); /* degenerate line */
#endif /* TRUST_NO_ONE */
#ifdef TRACK_INDEX_RANGE
track_index_range(el, v1);
track_index_range(el, v2);
#endif /* TRACK_INDEX_RANGE */
switch (el->index_type) {
case GL_UNSIGNED_BYTE:
{
GLubyte *indices = el->indices;
indices[offset] = v1;
indices[offset + 1] = v2;
break;
}
case GL_UNSIGNED_SHORT:
{
GLushort *indices = el->indices;
indices[offset] = v1;
indices[offset + 1] = v2;
break;
}
case GL_UNSIGNED_INT:
{
GLuint *indices = el->indices;
indices[offset] = v1;
indices[offset + 1] = v2;
break;
}
}
}
void GPUx_set_triangle_vertices(ElementList *el, unsigned prim_idx, unsigned v1, unsigned v2, unsigned v3)
{
const unsigned offset = prim_idx * 3;
#ifdef TRUST_NO_ONE
BLI_assert(el->prim_type == GL_TRIANGLES);
BLI_assert(prim_idx < el->prim_ct); /* prim out of range */
BLI_assert(v1 <= el->max_allowed_index && v2 <= el->max_allowed_index && v3 <= el->max_allowed_index); /* index out of range */
BLI_assert(v1 != v2 && v2 != v3 && v3 != v1); /* degenerate triangle */
#endif /* TRUST_NO_ONE */
#ifdef TRACK_INDEX_RANGE
track_index_range(el, v1);
track_index_range(el, v2);
track_index_range(el, v3);
#endif /* TRACK_INDEX_RANGE */
switch (el->index_type) {
case GL_UNSIGNED_BYTE:
{
GLubyte *indices = el->indices;
indices[offset] = v1;
indices[offset + 1] = v2;
indices[offset + 2] = v3;
break;
}
case GL_UNSIGNED_SHORT:
{
GLushort *indices = el->indices;
indices[offset] = v1;
indices[offset + 1] = v2;
indices[offset + 2] = v3;
break;
}
case GL_UNSIGNED_INT:
{
GLuint *indices = el->indices;
indices[offset] = v1;
indices[offset + 1] = v2;
indices[offset + 2] = v3;
break;
}
}
}
void GPUx_optimize(ElementList *el)
{
UNUSED_VARS(el);
/* TODO: apply Forsyth's vertex cache algorithm */
/* http://hacksoflife.blogspot.com/2010/01/to-strip-or-not-to-strip.html
* http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html <-- excellent
* http://home.comcast.net/%7Etom_forsyth/blog.wiki.html#%5B%5BRegular%20mesh%20vertex%20cache%20ordering%5D%5D */
/* Another opportunity: lines & triangles can have their verts rotated
* could use this for de-dup and cache optimization.
* line ab = ba
* triangle abc = bca = cab */
/* TODO: (optional) rearrange vertex attrib buffer to improve mem locality */
}
void GPUx_element_list_prime(ElementList *el)
{
#ifdef USE_ELEM_VBO
#ifdef TRUST_NO_ONE
BLI_assert(el->vbo_id == 0);
#endif /* TRUST_NO_ONE */
el->vbo_id = buffer_id_alloc();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, el->vbo_id);
/* fill with delicious data & send to GPU the first time only */
glBufferData(GL_ELEMENT_ARRAY_BUFFER, GPUx_element_list_size(el), el->indices, GL_STATIC_DRAW);
#ifdef KEEP_SINGLE_COPY
/* now that GL has a copy, discard original */
MEM_freeN(el->indices);
el->indices = NULL;
#endif /* KEEP_SINGLE_COPY */
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
#else
UNUSED_VARS(el);
#endif /* USE_ELEM_VBO */
}
void GPUx_element_list_use(const ElementList *el)
{
#ifdef USE_ELEM_VBO
#ifdef TRUST_NO_ONE
BLI_assert(el->vbo_id);
#endif /* TRUST_NO_ONE */
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, el->vbo_id);
#else
UNUSED_VARS(el);
#endif /* USE_ELEM_VBO */
}
void GPUx_element_list_done_using(const ElementList *el)
{
UNUSED_VARS(el);
#ifdef USE_ELEM_VBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
#endif /* USE_ELEM_VBO */
}

View File

@@ -0,0 +1,37 @@
#ifndef BLENDER_GL_ELEMENT_LIST_PRIVATE
#define BLENDER_GL_ELEMENT_LIST_PRIVATE
#include "GPUx_element.h"
#include <stdbool.h>
/* track min & max observed index (for glDrawRangeElements) */
#define TRACK_INDEX_RANGE
/* VBOs are guaranteed for any GL >= 1.5
* They can be turned off here (mostly for comparison). */
#define USE_ELEM_VBO
struct ElementList {
unsigned prim_ct;
GLenum prim_type; /* GL_POINTS, GL_LINES, GL_TRIANGLES */
GLenum index_type; /* GL_UNSIGNED_BYTE, _SHORT (ES), also _INT (full GL) */
unsigned max_allowed_index;
#ifdef TRACK_INDEX_RANGE
unsigned min_observed_index;
unsigned max_observed_index;
#endif /* TRACK_INDEX_RANGE */
#ifdef USE_ELEM_VBO
GLuint vbo_id;
#endif /* USE_ELEM_VBO */
void *indices; /* array of index_type */
};
unsigned min_index(const ElementList*);
unsigned max_index(const ElementList*);
const void *index_ptr(const ElementList*); /* for glDrawElements */
#endif /* BLENDER_GL_ELEMENT_LIST_PRIVATE */

View File

@@ -0,0 +1,277 @@
#include "GPUx_state.h"
#include "GPUx_vbo.h"
#include <string.h> /* memset */
#ifdef TRUST_NO_ONE
#include "BLI_utildefines.h"
#endif /* TRUST_NO_ONE */
const DrawState default_state = {
.common = {
.blend = false,
.depth_test = true,
.depth_write = true,
.lighting = false,
.interpolate = false
},
.point = {
.smooth = false,
.size = 1.0f
},
.line = {
.smooth = false,
.width = 1.0f,
.stipple = 0
},
.polygon = {
.draw_front = true,
.draw_back = true,
.material_id = MATERIAL_NONE,
.stipple = 0
}
};
static DrawState current;
static bool polygon_stipple_pattern_set = false;
/* TODO: these should be replicated once per GL context
* ^-- more of a MUSTDO */
void GPUx_reset_draw_state()
{
current = default_state;
GPUx_force_state_update();
}
void GPUx_set_common_state(const CommonDrawState *state)
{
if (state == NULL)
state = &default_state.common;
if (state->blend != current.common.blend) {
if (state->blend)
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
current.common.blend = state->blend;
}
if (state->depth_test != current.common.depth_test) {
if (state->depth_test)
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
current.common.depth_test = state->depth_test;
}
if (state->depth_write != current.common.depth_write) {
if (state->depth_write)
glDepthMask(1);
else
glDepthMask(0);
current.common.depth_write = state->depth_write;
}
if (state->lighting != current.common.lighting) {
if (state->lighting)
glEnable(GL_LIGHTING);
else
glDisable(GL_LIGHTING);
current.common.lighting = state->lighting;
}
if (state->interpolate != current.common.interpolate) {
if (state->interpolate)
glShadeModel(GL_SMOOTH);
else
glShadeModel(GL_FLAT);
current.common.interpolate = state->interpolate;
}
}
void GPUx_set_point_state(const PointDrawState *state)
{
if (state == NULL)
state = &default_state.point;
if (state->smooth != current.point.smooth) {
if (state->smooth)
glEnable(GL_POINT_SMOOTH);
else
glDisable(GL_POINT_SMOOTH);
current.point.smooth = state->smooth;
}
if (state->size != current.point.size) {
glPointSize(state->size);
current.point.size = state->size;
}
}
void GPUx_set_line_state(const LineDrawState *state)
{
if (state == NULL)
state = &default_state.line;
if (state->smooth != current.line.smooth) {
if (state->smooth)
glEnable(GL_LINE_SMOOTH);
else
glDisable(GL_LINE_SMOOTH);
current.line.smooth = state->smooth;
}
if (state->width != current.line.width) {
glLineWidth(state->width);
current.line.width = state->width;
}
if (state->stipple != current.line.stipple) {
if (state->stipple) {
const GLushort pattern = 0xAAAA;
glEnable(GL_LINE_STIPPLE);
/* line stipple is 16-bit pattern */
glLineStipple(state->stipple, pattern);
}
else
glDisable(GL_LINE_STIPPLE);
current.line.stipple = state->stipple;
}
}
static GLenum faces_to_cull(const PolygonDrawState *state)
{
/* https://www.opengl.org/wiki/Face_Culling */
if (!state->draw_front && !state->draw_back)
return GL_FRONT_AND_BACK;
else if (!state->draw_front)
return GL_FRONT;
else if (!state->draw_back)
return GL_BACK;
else
return GL_NONE; /* no culling */
}
void GPUx_set_polygon_state(const PolygonDrawState *state)
{
if (state == NULL)
state = &default_state.polygon;
if (state->draw_front != current.polygon.draw_front ||
state->draw_back != current.polygon.draw_back) {
const GLenum cull = faces_to_cull(state);
if (cull == GL_NONE)
glDisable(GL_CULL_FACE);
else {
const GLenum curr_cull = faces_to_cull(&current.polygon);
if (curr_cull == GL_NONE)
glEnable(GL_CULL_FACE);
glCullFace(cull);
}
current.polygon.draw_front = state->draw_front;
current.polygon.draw_back = state->draw_back;
}
if (state->material_id != current.polygon.material_id) {
/* TODO: whatever needed to make material active */
current.polygon.material_id = state->material_id;
}
if (state->stipple != current.polygon.stipple) {
if (state->stipple) {
glEnable(GL_POLYGON_STIPPLE);
if (!polygon_stipple_pattern_set) {
/* polygon stipple is 32x32-bit pattern */
GLubyte pattern[128];
memset(pattern, 0xAA, sizeof(pattern));
glPolygonStipple(pattern);
polygon_stipple_pattern_set = true;
}
}
else
glDisable(GL_POLYGON_STIPPLE);
current.polygon.stipple = state->stipple;
}
}
void GPUx_force_state_update()
{
const GLenum cull = faces_to_cull(&current.polygon);
/* TODO: factor some of this stuff out, share with set_*_state functions? */
/* common state */
if (current.common.blend)
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
if (current.common.depth_test)
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
if (current.common.depth_write)
glDepthMask(1);
else
glDepthMask(0);
if (current.common.lighting)
glEnable(GL_LIGHTING);
else
glDisable(GL_LIGHTING);
if (current.common.interpolate)
glShadeModel(GL_SMOOTH);
else
glShadeModel(GL_FLAT);
/* point state */
if (current.point.smooth)
glEnable(GL_POINT_SMOOTH);
else
glDisable(GL_POINT_SMOOTH);
glPointSize(current.point.size);
/* line state */
if (current.line.smooth)
glEnable(GL_LINE_SMOOTH);
else
glDisable(GL_LINE_SMOOTH);
glLineWidth(current.line.width);
if (current.line.stipple) {
const GLushort pattern = 0xAAAA;
glEnable(GL_LINE_STIPPLE);
/* line stipple is 16-bit pattern */
glLineStipple(current.line.stipple, pattern);
}
else
glDisable(GL_LINE_STIPPLE);
/* polygon state */
if (cull == GL_NONE)
glDisable(GL_CULL_FACE);
else {
glEnable(GL_CULL_FACE);
glCullFace(cull);
}
/* TODO: whatever needed to make material active */
if (current.polygon.stipple) {
GLubyte pattern[128];
glEnable(GL_POLYGON_STIPPLE);
/* polygon stipple is 32x32-bit pattern */
memset(pattern, 0xAA, sizeof(pattern));
glPolygonStipple(pattern);
polygon_stipple_pattern_set = true;
}
else
glDisable(GL_POLYGON_STIPPLE);
}

View File

@@ -0,0 +1,550 @@
#include "GPUx_vbo.h"
#include "gpux_buffer_id.h"
#include "GPU_extensions.h"
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
#include <stdlib.h>
#include <string.h>
#ifdef PRINT
#include <stdio.h>
#endif
/* VBOs are guaranteed for any GL >= 1.5
* They can be turned off here (mostly for comparison). */
#define USE_VBO
#ifdef USE_VBO
/* VAOs are part of GL 3.0, and optionally available in 2.1 as an extension:
* APPLE_vertex_array_object or ARB_vertex_array_object
* the ARB version of VAOs *must* use VBOs for vertex data
* so we should follow that restriction on all platforms. */
#define USE_VAO
/* keep vertex data in main mem or VRAM (not both) */
#define KEEP_SINGLE_COPY
#ifdef __linux__
#define MESA_WORKAROUND
/* For padded attributes (stride > size) Mesa likes the VBO to have some extra
* space at the end, else it drops those attributes of our final vertex.
* noticed this on Mesa 10.4.3 */
#endif
#endif
typedef unsigned char byte;
typedef struct {
GLenum comp_type;
unsigned comp_ct; /* 1 to 4 */
unsigned sz; /* size in bytes, 1 to 16 */
unsigned stride; /* natural stride in bytes, 1 to 16 */
VertexFetchMode fetch_mode;
#ifdef GENERIC_ATTRIB
char *name;
#else
GLenum array;
#endif
void *data;
/* TODO: more storage options
* - single VBO for all attribs (sequential)
* - single VBO, attribs interleaved
* - distinguish between static & dynamic attribs, w/ separate storage */
#ifdef USE_VBO
GLuint vbo_id;
#endif /* USE_VBO */
} Attrib;
static unsigned comp_sz(GLenum type)
{
const GLubyte sizes[] = {1,1,2,2,4,4,4}; /* uint32 might result in smaller code? */
#ifdef TRUST_NO_ONE
BLI_assert(type >= GL_BYTE && type <= GL_FLOAT);
#endif /* TRUST_NO_ONE */
return sizes[type - GL_BYTE];
}
static unsigned attrib_sz(const Attrib *a)
{
return a->comp_ct * comp_sz(a->comp_type);
}
static unsigned attrib_align(const Attrib *a)
{
const unsigned c = comp_sz(a->comp_type);
/* AMD HW can't fetch these well, so pad it out (other vendors too?) */
if (a->comp_ct == 3 && c <= 2)
return 4 * c;
else
return a->comp_ct * c;
}
struct VertexBuffer
{
unsigned attrib_ct; /* 1 to 16 */
unsigned vertex_ct;
#ifdef USE_VAO
GLuint vao_id;
#endif /* USE_VAO */
Attrib attribs[]; /* flexible array */
};
#ifdef PRINT
void GPUx_attrib_print(const VertexBuffer *buff, unsigned attrib_num)
{
unsigned int comp_size, v;
Attrib *a = buff->attribs + attrib_num;
unsigned type_idx = a->comp_type - GL_BYTE;
/* use GLSL names when they exist, or type_count for the others */
const char *singular[] = {"byte","ubyte","short","ushort","int","uint","float"};
const char *plural[] = {"byte_","ubyte_","short_","ushort_","ivec","uint_","vec"};
#ifdef GENERIC_ATTRIB
const char *var_name = a->name ? a->name : "foo";
#else
const char* var_name = "foo";
switch (a->array) {
case GL_VERTEX_ARRAY:
var_name = "gl_Vertex";
break;
case GL_NORMAL_ARRAY:
var_name = "gl_Normal";
break;
case GL_COLOR_ARRAY:
var_name = "gl_Color";
break;
case GL_TEXTURE_COORD_ARRAY:
var_name = "gl_MultiTexCoord0";
break;
default:
;
}
#endif
#ifdef TRUST_NO_ONE
BLI_assert(attrib_num < buff->attrib_ct);
BLI_assert(a->comp_type >= GL_BYTE && a->comp_type <= GL_FLOAT);
BLI_assert(a->data != NULL); /* attribute must be specified & in main mem */
#endif /* TRUST_NO_ONE */
if (a->comp_ct == 1)
printf("attrib %s %s = {\n", singular[type_idx], var_name);
else
printf("attrib %s%d %s = {\n", plural[type_idx], a->comp_ct, var_name);
comp_size = comp_sz(a->comp_type);
for (v = 0; v < buff->vertex_ct; ++v) {
unsigned int offset;
const void *data = (byte*)a->data + v * a->stride;
for (offset = 0; offset < a->sz; ++offset) {
if (offset % comp_size == 0)
putchar(' ');
printf("%02X", *(const byte*)data + offset);
}
putchar('\n');
}
puts("}");
}
#endif /* PRINT */
VertexBuffer *GPUx_vertex_buffer_create(unsigned a_ct, unsigned v_ct)
{
VertexBuffer *buff;
#ifdef TRUST_NO_ONE
BLI_assert(a_ct >= 1 && a_ct <= 16);
#ifdef USE_VAO
BLI_assert(GPU_vertex_array_object_support());
#endif /* USE_VBO */
#endif /* TRUST_NO_ONE */
buff = MEM_callocN(offsetof(VertexBuffer, attribs) + a_ct * sizeof(Attrib), "VertexBuffer");
buff->attrib_ct = a_ct;
buff->vertex_ct = v_ct;
return buff;
}
void GPUx_vertex_buffer_discard(VertexBuffer *buff)
{
unsigned a_idx;
for (a_idx = 0; a_idx < buff->attrib_ct; ++a_idx) {
Attrib *a = buff->attribs + a_idx;
#ifdef USE_VBO
if (a->vbo_id)
buffer_id_free(a->vbo_id);
#endif /* USE_VBO */
#ifdef GENERIC_ATTRIB
free(a->name);
#endif /* GENERIC_ATTRIB */
if (a->data)
MEM_freeN(a->data);
}
#ifdef USE_VAO
if (buff->vao_id)
vao_id_free(buff->vao_id);
#endif /* USE_VAO */
MEM_freeN(buff);
}
static unsigned attrib_total_size(const VertexBuffer *buff, unsigned attrib_num)
{
const Attrib *attrib = buff->attribs + attrib_num;
#ifdef TRUST_NO_ONE
BLI_assert(attrib_num < buff->attrib_ct);
#endif /* TRUST_NO_ONE */
#ifdef MESA_WORKAROUND
/* an over-estimate, with padding after each vertex */
return buff->vertex_ct * attrib->stride;
#else
/* just enough space for every vertex, with padding between but not after the last */
return (buff->vertex_ct - 1) * attrib->stride + attrib->sz;
#endif /* MESA_WORKAROUND */
}
unsigned GPUx_vertex_buffer_size(const VertexBuffer *buff)
{
unsigned sz = 0;
unsigned a_idx;
for (a_idx = 0; a_idx < buff->attrib_ct; ++a_idx)
sz += attrib_total_size(buff, a_idx);
return sz;
}
void GPUx_specify_attrib(VertexBuffer *buff, unsigned attrib_num,
#ifdef GENERIC_ATTRIB
const char *name,
#else
GLenum attrib_array,
#endif
GLenum comp_type, unsigned comp_ct, VertexFetchMode fetch_mode)
{
Attrib *attrib;
#ifdef TRUST_NO_ONE
BLI_assert(attrib_num < buff->attrib_ct);
BLI_assert(comp_type >= GL_BYTE && comp_type <= GL_FLOAT);
BLI_assert(comp_ct >= 1 && comp_ct <= 4);
if (comp_type == GL_FLOAT)
BLI_assert(fetch_mode == KEEP_FLOAT);
else {
BLI_assert(fetch_mode != KEEP_FLOAT);
if (fetch_mode == KEEP_INT)
BLI_assert(GPU_shader4_support());
}
#ifndef GENERIC_ATTRIB
/* classic (non-generic) attributes each have their quirks
* handle below */
switch (attrib_array) {
case GL_VERTEX_ARRAY:
BLI_assert(comp_type == GL_FLOAT || comp_type == GL_SHORT || comp_type == GL_INT);
if (comp_type != GL_FLOAT)
BLI_assert(fetch_mode == CONVERT_INT_TO_FLOAT);
BLI_assert(comp_ct >= 2);
break;
case GL_NORMAL_ARRAY:
BLI_assert(comp_type == GL_FLOAT || comp_type == GL_BYTE || comp_type == GL_SHORT || comp_type == GL_INT);
if (comp_type != GL_FLOAT)
BLI_assert(fetch_mode == NORMALIZE_INT_TO_FLOAT);
BLI_assert(comp_ct == 3);
break;
case GL_COLOR_ARRAY:
/* any comp_type allowed */
if (comp_type != GL_FLOAT)
BLI_assert(fetch_mode == NORMALIZE_INT_TO_FLOAT);
BLI_assert(comp_ct >= 3);
break;
case GL_TEXTURE_COORD_ARRAY:
BLI_assert(comp_type == GL_FLOAT || comp_type == GL_SHORT || comp_type == GL_INT);
if (comp_type != GL_FLOAT)
BLI_assert(fetch_mode == CONVERT_INT_TO_FLOAT);
break;
/* not supporting these:
* GL_INDEX_ARRAY
* GL_SECONDARY_COLOR_ARRAY
* GL_EDGE_FLAG_ARRAY
* GL_FOG_COORD_ARRAY
*/
default:
BLI_assert(false); /* bad or unsupported array */
}
BLI_assert(fetch_mode != KEEP_INT); /* glVertexPointer and friends have no int variants */
/* TODO: allow only one of each type of array (scan other attribs) */
#endif
#endif /* TRUST_NO_ONE */
attrib = buff->attribs + attrib_num;
#ifdef GENERIC_ATTRIB
attrib->name = strdup(name);
#else
attrib->array = attrib_array;
#endif /* GENERIC_ATTRIB */
attrib->comp_type = comp_type;
attrib->comp_ct = comp_ct;
attrib->sz = attrib_sz(attrib);
attrib->stride = attrib_align(attrib);
attrib->fetch_mode = fetch_mode;
attrib->data = MEM_mallocN(attrib_total_size(buff, attrib_num), "Attrib.data");
#ifdef PRINT
GPUx_attrib_print(buff, attrib_num);
#endif /* PRINT */
}
#ifdef GENERIC_ATTRIB
void GPUx_bind_attrib_locations(const VertexBuffer *buff, GLuint program)
{
unsigned a_idx;
#ifdef TRUST_NO_ONE
BLI_assert(glIsProgram(program));
#endif
for (a_idx = 0; a_idx < buff->attrib_ct; ++a_idx) {
const Attrib *a = buff->attribs + a_idx;
glBindAttribLocation(program, a_idx, a->name);
}
}
#endif /* GENERIC_ATTRIB */
void GPUx_set_attrib(VertexBuffer *buff, unsigned attrib_num, unsigned vertex_num, const void *data)
{
Attrib *attrib = buff->attribs + attrib_num;
#ifdef TRUST_NO_ONE
BLI_assert(attrib_num < buff->attrib_ct);
BLI_assert(vertex_num < buff->vertex_ct);
BLI_assert(attrib->data != NULL); /* attribute must be specified & in main mem */
#endif /* TRUST_NO_ONE */
memcpy((byte*)attrib->data + vertex_num * attrib->stride, data, attrib->sz);
}
void GPUx_set_attrib_2f(VertexBuffer *buff, unsigned attrib_num, unsigned vertex_num, float x, float y)
{
const GLfloat data[] = { x, y };
#ifdef TRUST_NO_ONE
Attrib *attrib = buff->attribs + attrib_num;
BLI_assert(attrib->comp_type == GL_FLOAT);
BLI_assert(attrib->comp_ct == 2);
#endif /* TRUST_NO_ONE */
GPUx_set_attrib(buff, attrib_num, vertex_num, data);
}
void GPUx_set_attrib_3f(VertexBuffer *buff, unsigned attrib_num, unsigned vertex_num, float x, float y, float z)
{
const GLfloat data[] = { x, y, z };
#ifdef TRUST_NO_ONE
Attrib *attrib = buff->attribs + attrib_num;
BLI_assert(attrib->comp_type == GL_FLOAT);
BLI_assert(attrib->comp_ct == 3);
#endif /* TRUST_NO_ONE */
GPUx_set_attrib(buff, attrib_num, vertex_num, data);
}
void GPUx_fill_attrib(VertexBuffer *buff, unsigned attrib_num, const void *data)
{
Attrib *attrib = buff->attribs + attrib_num;
#ifdef TRUST_NO_ONE
BLI_assert(attrib_num < buff->attrib_ct);
BLI_assert(attrib->data != NULL); /* attribute must be specified & in main mem */
#endif /* TRUST_NO_ONE */
if (attrib->sz == attrib->stride) {
/* tightly packed, so we can copy it all at once */
memcpy(attrib->data, data, buff->vertex_ct * attrib->sz);
}
else {
unsigned v;
/* not tightly packed, so we must copy it per vertex
* (this is begging for vector (SSE) coding) */
for (v = 0; v < buff->vertex_ct; ++v)
memcpy((byte*)attrib->data + v * attrib->stride, (byte*)data + v * attrib->sz, attrib->sz);
}
}
void GPUx_fill_attrib_stride(VertexBuffer *buff, unsigned attrib_num, const void *data, unsigned stride)
{
Attrib *attrib = buff->attribs + attrib_num;
#ifdef TRUST_NO_ONE
BLI_assert(attrib_num < buff->attrib_ct);
BLI_assert(attrib->data != NULL); /* attribute must be specified & in main mem */
BLI_assert(stride >= attrib->sz); /* no overlapping attributes (legal but weird) */
#endif /* TRUST_NO_ONE */
if (stride == attrib->stride) {
/* natural stride used, so we can copy it all at once */
memcpy(attrib->data, data, buff->vertex_ct * attrib->sz);
}
else {
unsigned v;
/* we must copy it per vertex */
for (v = 0; v < buff->vertex_ct; ++v)
memcpy((byte*)attrib->data + v * attrib->stride, (byte*)data + v * stride, attrib->sz);
}
}
void GPUx_vertex_buffer_prime(VertexBuffer *buff)
{
unsigned a_idx;
#ifdef USE_VAO
#ifdef TRUST_NO_ONE
BLI_assert(buff->vao_id == 0);
#endif /* TRUST_NO_ONE */
buff->vao_id = vao_id_alloc();
glBindVertexArray(buff->vao_id);
#endif /* USE_VAO */
#ifdef USE_VBO
for (a_idx = 0; a_idx < buff->attrib_ct; ++a_idx) {
Attrib *a = buff->attribs + a_idx;
#ifdef USE_VAO
#ifdef GENERIC_ATTRIB
glEnableVertexAttribArray(a_idx);
#else
glEnableClientState(a->array);
#endif /* GENERIC_ATTRIB */
#endif /* USE_VAO */
#ifdef TRUST_NO_ONE
BLI_assert(a->vbo_id == 0);
#endif /* TRUST_NO_ONE */
a->vbo_id = buffer_id_alloc();
glBindBuffer(GL_ARRAY_BUFFER, a->vbo_id);
/* fill with delicious data & send to GPU the first time only */
glBufferData(GL_ARRAY_BUFFER, attrib_total_size(buff, a_idx), a->data, GL_STATIC_DRAW);
#ifdef KEEP_SINGLE_COPY
/* now that GL has a copy, discard original */
MEM_freeN(a->data);
a->data = NULL;
#endif /* KEEP_SINGLE_COPY */
#ifdef USE_VAO
#ifdef GENERIC_ATTRIB
switch (a->fetch_mode) {
case KEEP_FLOAT:
case CONVERT_INT_TO_FLOAT:
glVertexAttribPointer(a_idx, a->comp_ct, a->comp_type, GL_FALSE, a->stride, 0);
break;
case NORMALIZE_INT_TO_FLOAT:
glVertexAttribPointer(a_idx, a->comp_ct, a->comp_type, GL_TRUE, a->stride, 0);
break;
case KEEP_INT:
glVertexAttribIPointerEXT(a_idx, a->comp_ct, a->comp_type, a->stride, 0);
}
#else /* classic (non-generic) attributes */
switch (a->array) {
case GL_VERTEX_ARRAY:
glVertexPointer(a->comp_ct, a->comp_type, a->stride, 0);
break;
case GL_NORMAL_ARRAY:
glNormalPointer(a->comp_type, a->stride, 0);
break;
case GL_COLOR_ARRAY:
glColorPointer(a->comp_ct, a->comp_type, a->stride, 0);
break;
case GL_TEXTURE_COORD_ARRAY:
glTexCoordPointer(a->comp_ct, a->comp_type, a->stride, 0);
break;
default:
;
}
#endif /* GENERIC_ATTRIB */
#endif /* USE_VAO */
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
#else
UNUSED_VARS(a_idx, buff);
#endif /* USE_VBO */
#ifdef USE_VAO
glBindVertexArray(0);
#endif /* USE_VAO */
}
void GPUx_vertex_buffer_use(const VertexBuffer *buff)
{
#ifdef USE_VAO
#ifdef TRUST_NO_ONE
BLI_assert(buff->vao_id);
#endif /* TRUST_NO_ONE */
/* simply bind & exit */
glBindVertexArray(buff->vao_id);
#else
unsigned int a_idx;
for (a_idx = 0; a_idx < buff->attrib_ct; ++a_idx) {
Attrib *a = buff->attribs + a_idx;
const void *data;
#ifdef GENERIC_ATTRIB
glEnableVertexAttribArray(a_idx);
#else
glEnableClientState(a->array);
#endif /* GENERIC_ATTRIB */
#ifdef USE_VBO
#ifdef TRUST_NO_ONE
BLI_assert(a->vbo_id);
#endif /* TRUST_NO_ONE */
glBindBuffer(GL_ARRAY_BUFFER, a->vbo_id);
data = 0;
#else /* client vertex array */
data = a->data;
#endif /* USE_VBO */
#ifdef GENERIC_ATTRIB
switch (a->fetch_mode) {
case KEEP_FLOAT:
case CONVERT_INT_TO_FLOAT:
glVertexAttribPointer(a_idx, a->comp_ct, a->comp_type, GL_FALSE, a->stride, data);
break;
case NORMALIZE_INT_TO_FLOAT:
glVertexAttribPointer(a_idx, a->comp_ct, a->comp_type, GL_TRUE, a->stride, data);
break;
case KEEP_INT:
glVertexAttribIPointerEXT(a_idx, a->comp_ct, a->comp_type, a->stride, data);
}
#else /* classic (non-generic) attributes */
switch (a->array) {
case GL_VERTEX_ARRAY:
glVertexPointer(a->comp_ct, a->comp_type, a->stride, data);
break;
case GL_NORMAL_ARRAY:
glNormalPointer(a->comp_type, a->stride, data);
break;
case GL_COLOR_ARRAY:
glColorPointer(a->comp_ct, a->comp_type, a->stride, data);
break;
case GL_TEXTURE_COORD_ARRAY:
glTexCoordPointer(a->comp_ct, a->comp_type, a->stride, data);
break;
default:
;
}
#endif /* GENERIC_ATTRIB */
}
#ifdef USE_VBO
glBindBuffer(GL_ARRAY_BUFFER, 0);
#endif /* USE_VBO */
#endif /* USE_VAO */
}
void GPUx_vertex_buffer_done_using(const VertexBuffer *buff)
{
#ifdef USE_VAO
UNUSED_VARS(buff);
glBindVertexArray(0);
#else
unsigned int a_idx;
for (a_idx = 0; a_idx < buff->attrib_ct; ++a_idx) {
#ifdef GENERIC_ATTRIB
glDisableVertexAttribArray(a_idx);
#else
glDisableClientState(buff->attribs[a_idx].array);
#endif /* GENERIC_ATTRIB */
}
#endif /* USE_VAO */
}
unsigned GPUx_vertex_ct(const VertexBuffer *buff)
{
return buff->vertex_ct;
}

View File

@@ -222,6 +222,7 @@ typedef struct PreviewImage {
#define ID_LS MAKE_ID2('L', 'S') /* FreestyleLineStyle */
#define ID_PAL MAKE_ID2('P', 'L') /* Palette */
#define ID_PC MAKE_ID2('P', 'C') /* PaintCurve */
#define ID_GPUWS MAKE_ID2('G', 'W') /* GPUWorkflowShader */
/* NOTE! Fake IDs, needed for g.sipo->blocktype or outliner */
#define ID_SEQ MAKE_ID2('S', 'Q')

View File

@@ -394,6 +394,7 @@ typedef struct bNodeTree {
#define NTREE_SHADER 0
#define NTREE_COMPOSIT 1
#define NTREE_TEXTURE 2
#define NTREE_WORKFLOW 3
/* ntree->init, flag */
#define NTREE_TYPE_INIT 1
@@ -840,6 +841,18 @@ typedef struct NodeShaderScript {
char *bytecode;
} NodeShaderScript;
typedef struct NodeShaderScriptGLSL {
/* XXX merwin: what is needed here? */
int mode; /* ok, use same values */
int flag; /* ok, use same flag */
char filepath[1024]; /* 1024 = FILE_MAX */
/* v-- don't need these though */
/* char bytecode_hash[64]; */
/* char *bytecode; */
} NodeShaderScriptGLSL;
typedef struct NodeShaderTangent {
int direction_type;
int axis;

View File

@@ -739,6 +739,7 @@ typedef enum eOpenGL_RenderingOptions {
USER_DISABLE_MIPMAP = (1 << 2),
USER_DISABLE_VBO = (1 << 3),
/* USER_DISABLE_AA = (1 << 4), */ /* DEPRECATED */
USER_VIEWPORT_2 = (1 << 5),
} eOpenGL_RenderingOptions;
/* selection method for opengl gpu_select_method */

View File

@@ -61,6 +61,8 @@ struct GPUFX;
#include "DNA_movieclip_types.h"
#include "DNA_gpu_types.h"
struct bNodeTree;
/* ******************************** */
/* The near/far thing is a Win EXCEPTION. Thus, leave near/far in the
@@ -81,6 +83,16 @@ typedef struct BGpic {
char pad[6];
} BGpic;
typedef struct GPUWorkflowShader {
ID id;
int objectmode; /* object modes for which this workflow applies */
int use_material; /* workflow shader is overlaid over materials of the meshes */
int datamask; /* datamask of the data that will be required for this workflow shader */
int pad;
struct bNodeTree *nodetree; /* node tree that describes the shader */
} GPUWorkflowShader;
/* ********************************* */
typedef struct RegionView3D {
@@ -229,6 +241,7 @@ typedef struct View3D {
/* XXX deprecated? */
struct bGPdata *gpd DNA_DEPRECATED; /* Grease-Pencil Data (annotation layers) */
struct GPUWorkflowShader *activeworkflow;
/* multiview - stereo 3d */
short stereo3d_flag;

View File

@@ -259,6 +259,7 @@ extern StructRNA RNA_GPencilFrame;
extern StructRNA RNA_GPencilLayer;
extern StructRNA RNA_GPencilStroke;
extern StructRNA RNA_GPencilStrokePoint;
extern StructRNA RNA_GPUWorkflowShader;
extern StructRNA RNA_GameBooleanProperty;
extern StructRNA RNA_GameFloatProperty;
extern StructRNA RNA_GameIntProperty;
@@ -514,6 +515,7 @@ extern StructRNA RNA_ShaderNodeNormal;
extern StructRNA RNA_ShaderNodeGamma;
extern StructRNA RNA_ShaderNodeOutput;
extern StructRNA RNA_ShaderNodeScript;
extern StructRNA RNA_ShaderNodeScriptGLSL;
extern StructRNA RNA_ShaderNodeRGB;
extern StructRNA RNA_ShaderNodeRGBCurve;
extern StructRNA RNA_ShaderNodeRGBToBW;
@@ -675,6 +677,7 @@ extern StructRNA RNA_WindowManager;
extern StructRNA RNA_WipeSequence;
extern StructRNA RNA_WireframeModifier;
extern StructRNA RNA_WoodTexture;
extern StructRNA RNA_WorkflowNodeTree;
extern StructRNA RNA_World;
extern StructRNA RNA_WorldAmbientOcclusion;
extern StructRNA RNA_WorldLighting;

View File

@@ -159,6 +159,7 @@ short RNA_type_to_ID_code(StructRNA *type)
if (RNA_struct_is_a(type, &RNA_VectorFont)) return ID_VF;
if (RNA_struct_is_a(type, &RNA_World)) return ID_WO;
if (RNA_struct_is_a(type, &RNA_WindowManager)) return ID_WM;
if (RNA_struct_is_a(type, &RNA_GPUWorkflowShader)) return ID_GPUWS;
return 0;
}
@@ -198,6 +199,7 @@ StructRNA *ID_code_to_RNA_type(short idcode)
case ID_VF: return &RNA_VectorFont;
case ID_WM: return &RNA_WindowManager;
case ID_WO: return &RNA_World;
case ID_GPUWS: return &RNA_GPUWorkflowShader;
default: return &RNA_ID;
}

View File

@@ -2951,6 +2951,50 @@ static void rna_ShaderNodeScript_update(Main *bmain, Scene *scene, PointerRNA *p
ED_node_tag_update_nodetree(bmain, ntree);
}
static void rna_ShaderNodeScriptGLSL_mode_set(PointerRNA *ptr, int value)
{
bNode *node = (bNode *)ptr->data;
NodeShaderScriptGLSL *nss = node->storage;
if (nss->mode != value) {
nss->mode = value;
nss->filepath[0] = '\0';
nss->flag &= ~NODE_SCRIPT_AUTO_UPDATE;
/* replace text datablock by filepath */
if (node->id) {
Text *text = (Text *)node->id;
if (value == NODE_SCRIPT_EXTERNAL && text->name) {
BLI_strncpy(nss->filepath, text->name, sizeof(nss->filepath));
BLI_path_rel(nss->filepath, G.main->name);
}
id_us_min(node->id);
node->id = NULL;
}
}
}
static void rna_ShaderNodeScriptGLSL_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
/* TODO: the right thing --merwin */
#if 0
bNodeTree *ntree = (bNodeTree *)ptr->id.data;
bNode *node = (bNode *)ptr->data;
RenderEngineType *engine_type = RE_engines_find(scene->r.engine);
if (engine_type && engine_type->update_script_node) {
/* auto update node */
RenderEngine *engine = RE_engine_create(engine_type);
engine_type->update_script_node(engine, ntree, node);
RE_engine_free(engine);
}
ED_node_tag_update_nodetree(bmain, ntree);
#endif
}
static void rna_ShaderNodeSubsurface_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->id.data;
@@ -4034,6 +4078,40 @@ static void def_sh_script(StructRNA *srna)
#endif
}
static void def_sh_script_glsl(StructRNA *srna)
{
PropertyRNA *prop;
prop = RNA_def_property(srna, "script_glsl", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "id");
RNA_def_property_struct_type(prop, "Text");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_ui_text(prop, "Script", "Internal shader script to define the shader");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNodeScriptGLSL_update");
RNA_def_struct_sdna_from(srna, "NodeShaderScriptGLSL", "storage");
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
RNA_def_property_ui_text(prop, "File Path", "Shader script path");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNodeScriptGLSL_update");
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_funcs(prop, NULL, "rna_ShaderNodeScriptGLSL_mode_set", NULL);
RNA_def_property_enum_items(prop, node_script_mode_items);
RNA_def_property_ui_text(prop, "Script Source", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "use_auto_update", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_SCRIPT_AUTO_UPDATE);
RNA_def_property_ui_text(prop, "Auto Update",
"Automatically update the shader when the .glsl file changes (external scripts only)");
/* needs to be reset to avoid bad pointer type in API functions below */
RNA_def_struct_sdna_from(srna, "bNode", NULL);
/* API functions */
}
/* -- Compositor Nodes ------------------------------------------------------ */
static void def_cmp_alpha_over(StructRNA *srna)
@@ -7693,6 +7771,7 @@ static void rna_def_nodetree(BlenderRNA *brna)
static EnumPropertyItem static_type_items[] = {
{NTREE_SHADER, "SHADER", ICON_MATERIAL, "Shader", "Shader nodes"},
{NTREE_WORKFLOW, "WORKFLOW", ICON_SMOOTH, "Workflow", "Workflow nodes"},
{NTREE_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture nodes"},
{NTREE_COMPOSIT, "COMPOSITING", ICON_RENDERLAYERS, "Compositing", "Compositing nodes"},
{0, NULL, 0, NULL, NULL}
@@ -7876,6 +7955,18 @@ static void rna_def_shader_nodetree(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_MATERIAL);
}
static void rna_def_workflow_nodetree(BlenderRNA *brna)
{
StructRNA *srna;
srna = RNA_def_struct(brna, "WorkflowNodeTree", "NodeTree");
RNA_def_struct_ui_text(srna, "Workflow Node Tree",
"Node tree consisting of linked nodes used for shader workflows");
RNA_def_struct_sdna(srna, "bNodeTree");
RNA_def_struct_ui_icon(srna, ICON_SMOOTH);
}
static void rna_def_texture_nodetree(BlenderRNA *brna)
{
StructRNA *srna;
@@ -7972,6 +8063,7 @@ void RNA_def_nodetree(BlenderRNA *brna)
rna_def_composite_nodetree(brna);
rna_def_shader_nodetree(brna);
rna_def_workflow_nodetree(brna);
rna_def_texture_nodetree(brna);
#define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
@@ -7994,6 +8086,7 @@ void RNA_def_nodetree(BlenderRNA *brna)
define_specific_node(brna, "ShaderNodeGroup", "ShaderNode", "Group", "", def_group);
define_specific_node(brna, "CompositorNodeGroup", "CompositorNode", "Group", "", def_group);
define_specific_node(brna, "TextureNodeGroup", "TextureNode", "Group", "", def_group);
define_specific_node(brna, "WorkflowNodeGroup", "TextureNode", "Group", "", def_group);
def_custom_group(brna);
/* special socket types */

View File

@@ -2031,6 +2031,21 @@ static void rna_def_space_outliner(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
}
static void rna_def_workflow_shader(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "GPUWorkflowShader", "ID");
RNA_def_struct_sdna(srna, "GPUWorkflowShader");
RNA_def_struct_ui_text(srna, "Workflow Shader", "Drawing definition in the 3D viewport");
prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "nodetree");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_CONTEXT_UPDATE);
RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node based worlds");
}
static void rna_def_background_image(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2347,6 +2362,11 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Viewport Shading", "Method to display/shade objects in the 3D View");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_viewport_shade_update");
prop = RNA_def_property(srna, "activeworkflow", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Shading Workflow", "Method to display/shade objects in the 3D View");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_viewport_shade_update");
prop = RNA_def_property(srna, "local_view", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "localvd");
RNA_def_property_ui_text(prop, "Local View",
@@ -4548,6 +4568,7 @@ void RNA_def_space(BlenderRNA *brna)
rna_def_filemenu_entry(brna);
rna_def_space_filebrowser(brna);
rna_def_space_outliner(brna);
rna_def_workflow_shader(brna);
rna_def_background_image(brna);
rna_def_space_view3d(brna);
rna_def_space_buttons(brna);

View File

@@ -4045,6 +4045,13 @@ static void rna_def_userdef_system(BlenderRNA *brna)
/* this isn't essential but nice to check if VBO draws any differently */
RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_vbo_update");
prop = RNA_def_property(srna, "use_viewport_new", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "gameflags", USER_VIEWPORT_2);
RNA_def_property_ui_text(prop, "Viewport 2",
"Use new viewport code in viewport");
/* this isn't essential but nice to check if VBO draws any differently */
RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_vbo_update");
prop = RNA_def_property(srna, "anisotropic_filter", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "anisotropic_filter");
RNA_def_property_enum_items(prop, anisotropic_items);

View File

@@ -174,6 +174,7 @@ set(SRC
shader/nodes/node_shader_bump.c
shader/nodes/node_shader_emission.c
shader/nodes/node_shader_fresnel.c
shader/nodes/node_shader_script_glsl.c
shader/nodes/node_shader_geometry.c
shader/nodes/node_shader_holdout.c
shader/nodes/node_shader_layer_weight.c

View File

@@ -35,6 +35,7 @@
#include "BKE_node.h"
extern struct bNodeTreeType *ntreeType_Shader;
extern struct bNodeTreeType *ntreeType_Workflow;
/* the type definitions array */
@@ -42,6 +43,8 @@ extern struct bNodeTreeType *ntreeType_Shader;
void register_node_tree_type_sh(void);
void register_node_tree_type_workflow(void);
void register_node_type_sh_group(void);
void register_node_type_sh_output(void);
@@ -90,6 +93,7 @@ void register_node_type_sh_tex_coord(void);
void register_node_type_sh_particle_info(void);
void register_node_type_sh_hair_info(void);
void register_node_type_sh_script(void);
void register_node_type_sh_script_glsl(void);
void register_node_type_sh_normal_map(void);
void register_node_type_sh_tangent(void);
void register_node_type_sh_vect_transform(void);

View File

@@ -105,6 +105,7 @@ DefNode( ShaderNode, SH_NODE_BUMP, def_sh_bump, "BU
DefNode( ShaderNode, SH_NODE_NORMAL_MAP, def_sh_normal_map, "NORMAL_MAP", NormalMap, "Normal Map", "" )
DefNode( ShaderNode, SH_NODE_TANGENT, def_sh_tangent, "TANGENT", Tangent, "Tangent", "" )
DefNode( ShaderNode, SH_NODE_SCRIPT, def_sh_script, "SCRIPT", Script, "Script", "" )
DefNode( ShaderNode, SH_NODE_SCRIPT_GLSL, def_sh_script_glsl, "SCRIPT_GLSL", ScriptGLSL, "ScriptGLSL", "" )
DefNode( ShaderNode, SH_NODE_TEX_IMAGE, def_sh_tex_image, "TEX_IMAGE", TexImage, "Image Texture", "" )
DefNode( ShaderNode, SH_NODE_TEX_ENVIRONMENT, def_sh_tex_environment, "TEX_ENVIRONMENT", TexEnvironment, "Environment Texture","" )
DefNode( ShaderNode, SH_NODE_TEX_SKY, def_sh_tex_sky, "TEX_SKY", TexSky, "Sky Texture", "" )

View File

@@ -36,7 +36,9 @@
#include "DNA_material_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_world_types.h"
#include "DNA_linestyle_types.h"
@@ -50,6 +52,7 @@
#include "BKE_linestyle.h"
#include "BKE_node.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "RNA_access.h"
@@ -197,6 +200,71 @@ void register_node_tree_type_sh(void)
ntreeTypeAdd(tt);
}
static void workflow_get_from_context(const bContext *C, bNodeTreeType *UNUSED(treetype), bNodeTree **r_ntree, ID **r_id, ID **r_from)
{
Main *bmain = CTX_data_main(C);
ScrArea *sa = NULL;
ARegion *ar = NULL;
View3D *v3d = NULL;
bScreen *screen = CTX_wm_screen(C);
*r_from = NULL;
if (screen) {
sa = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0);
ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
if (ar) {
v3d = sa->spacedata.first;
}
}
if (v3d && v3d->activeworkflow) {
*r_id = &v3d->activeworkflow->id;
*r_ntree = v3d->activeworkflow->nodetree;
}
else if (bmain->gpuworkflows.first) {
GPUWorkflowShader *wfshader = bmain->gpuworkflows.first;
*r_id = &wfshader->id;
*r_ntree = wfshader->nodetree;
}
else {
*r_id = NULL;
*r_ntree = NULL;
}
}
static int workflow_tree_poll(const bContext *UNUSED(C), bNodeTreeType *UNUSED(treetype))
{
return (U.gameflags & USER_VIEWPORT_2) != 0;
}
bNodeTreeType *ntreeType_Workflow;
void register_node_tree_type_workflow(void)
{
bNodeTreeType *tt = ntreeType_Workflow = MEM_callocN(sizeof(bNodeTreeType), "shader node tree type");
tt->type = NTREE_WORKFLOW;
strcpy(tt->idname, "WorkflowNodeTree");
strcpy(tt->ui_name, "Workflow");
tt->ui_icon = 0; /* defined in drawnode.c */
strcpy(tt->ui_description, "Workflow nodes");
tt->foreach_nodeclass = foreach_nodeclass;
tt->localize = localize;
tt->local_sync = local_sync;
tt->local_merge = local_merge;
tt->update = update;
tt->poll = workflow_tree_poll;
tt->get_from_context = workflow_get_from_context;
tt->ext.srna = &RNA_WorkflowNodeTree;
ntreeTypeAdd(tt);
}
/* GPU material from shader nodes */
void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat, short compatibility)

View File

@@ -0,0 +1,76 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2005 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/nodes/shader/nodes/node_shader_script_glsl.c
* \ingroup shdnodes
*/
#include "node_shader_util.h"
/* **************** Script ******************** */
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeShaderScriptGLSL *nss = MEM_callocN(sizeof(NodeShaderScriptGLSL), "GLSL shader script node");
node->storage = nss;
}
static void node_free_glsl(bNode *node)
{
NodeShaderScriptGLSL *nss = node->storage;
if (nss) {
// if (nss->bytecode) {
// MEM_freeN(nss->bytecode);
// }
MEM_freeN(nss);
}
}
static void node_copy_glsl(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, bNode *src_node)
{
NodeShaderScriptGLSL *src_nss = src_node->storage;
NodeShaderScriptGLSL *dest_nss = MEM_dupallocN(src_nss);
// if (src_nss->bytecode)
// dest_nss->bytecode = MEM_dupallocN(src_nss->bytecode);
dest_node->storage = dest_nss;
}
void register_node_type_sh_script_glsl(void)
{
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_SCRIPT_GLSL, "ScriptGLSL", NODE_CLASS_SCRIPT, 0);
node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_init(&ntype, init);
node_type_storage(&ntype, "NodeShaderScriptGLSL", node_free_glsl, node_copy_glsl);
nodeRegisterType(&ntype);
}