новая структура проекта

This commit is contained in:
2026-04-20 21:04:25 +04:00
parent 1fe2a72ef1
commit 1a56b22e38
1932 changed files with 1886 additions and 22779 deletions
@@ -0,0 +1,133 @@
import traceback
from bgl import *
def glCheckError(title):
err = glGetError()
if err == GL_NO_ERROR:
return
derrs = {
GL_INVALID_ENUM: 'invalid enum',
GL_INVALID_VALUE: 'invalid value',
GL_INVALID_OPERATION: 'invalid operation',
GL_OUT_OF_MEMORY: 'out of memory',
GL_INVALID_FRAMEBUFFER_OPERATION: 'invalid framebuffer operation',
}
if err in derrs:
print('ERROR (%s): %s' % (title, derrs[err]))
else:
print('ERROR (%s): code %d' % (title, err))
traceback.print_stack()
def check_framebuffer_status(target):
status = glCheckFramebufferStatus(target)
if status == GL_FRAMEBUFFER_COMPLETE:
return True
elif status == GL_FRAMEBUFFER_UNDEFINED:
print("framebuffer not complete: GL_FRAMEBUFFER_UNDEFINED - returned if the specified framebuffer is the default read or draw framebuffer, but the default framebuffer does not exist.")
elif status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT - returned if any of the framebuffer attachment points are framebuffer incomplete.")
elif status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT - returned if the framebuffer does not have at least one image attached to it.")
elif status == GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER - returned if the value of GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for any color attachment point named by GL_DRAW_BUFFERi.")
elif status == GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER - returned if GL_READ_BUFFER is not GL_NONE and the value of GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for the color attachment point named by GL_READ_BUFFER.")
elif status == GL_FRAMEBUFFER_UNSUPPORTED:
print("framebuffer not complete: GL_FRAMEBUFFER_UNSUPPORTED - returned if the combination of internal formats of the attached images violates an implementation-dependent set of restrictions.")
elif status == GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE - returned if the value of GL_RENDERBUFFER_SAMPLES is not the same for all attached renderbuffers; if the value of GL_TEXTURE_SAMPLES is the not same for all attached textures; or, if the attached images are a mix of renderbuffers and textures, the value of GL_RENDERBUFFER_SAMPLES does not match the value of GL_TEXTURE_SAMPLES. also returned if the value of GL_TEXTURE_FIXED_SAMPLE_LOCATIONS i s not the same for all attached textures; or, if the attached images are a mix of renderbuffers and textures, the value of GL_TEXTURE_FIXED_SAMPLE_LOCATIONS is not GL_TRUE for all attached textures.")
elif status == GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS - returned if any framebuffer attachment is layered, and any populated attachment is not layered, or if all populated color attachments are not from textures of the same target.")
else:
print("framebuffer not complete: status 0x%x (unknown)" % (status,))
return False
def create_image(width, height, target=GL_RGBA):
"""create an empty image, dimensions pow2"""
if target == GL_RGBA:
target, internal_format, dimension = GL_RGBA, GL_RGB, 3
else:
target, internal_format, dimension = GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, 1
null_buffer = Buffer(GL_BYTE, [(width + 1) * (height + 1) * dimension])
id_buf = Buffer(GL_INT, 1)
glGenTextures(1, id_buf)
tex_id = id_buf.to_list()[0]
glBindTexture(GL_TEXTURE_2D, tex_id)
glTexImage2D(GL_TEXTURE_2D, 0, target, width, height, 0, internal_format, GL_UNSIGNED_BYTE, null_buffer)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
if target == GL_DEPTH_COMPONENT32:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE)
glCopyTexImage2D(GL_TEXTURE_2D, 0, target, 0, 0, width, height, 0)
glBindTexture(GL_TEXTURE_2D, 0)
del null_buffer
return tex_id
def delete_image(tex_id):
"""clear created image"""
id_buf = Buffer(GL_INT, 1)
id_buf.to_list()[0] = tex_id
if glIsTexture(tex_id):
glDeleteTextures(1, id_buf)
def create_framebuffer(width, height, target=GL_RGBA):
"""create an empty framebuffer"""
id_buf = Buffer(GL_INT, 1)
glGenFramebuffers(1, id_buf)
fbo_id = id_buf.to_list()[0]
if fbo_id == 0:
print("Framebuffer error on creation")
return -1
tex_id = create_image(width, height)
glBindFramebuffer(GL_FRAMEBUFFER, fbo_id)
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex_id, 0)
glGenRenderbuffers(1, id_buf)
depth_id = id_buf.to_list()[0]
glBindRenderbuffer(GL_RENDERBUFFER, depth_id)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, width, height)
# attach the depth buffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_id)
#glDrawBuffers(fbo_id, GL_COLOR_ATTACHMENT0)
if not check_framebuffer_status(GL_DRAW_FRAMEBUFFER):
delete_framebuffer(fbo_id)
glBindFramebuffer(GL_FRAMEBUFFER, 0)
return -1
glBindFramebuffer(GL_FRAMEBUFFER, 0)
return fbo_id
def delete_framebuffer(fbo_id):
"""clear created framebuffer"""
id_buf = Buffer(GL_INT, 1)
id_buf.to_list()[0] = fbo_id
if glIsFramebuffer(fbo_id):
glDeleteFramebuffers(1, id_buf)
@@ -0,0 +1,186 @@
import bpy
import gpu
import mathutils
from typing import Union
from bgl import *
from .drawing_elements import ElementTypes
from .utils import render_debug
from .bgl_ext import glCheckError
class DrawingBatch:
"""Abstract base class defining an interface of a drawing batch (drawing element)."""
c_batch: Union['CM2DrawingBatch', 'CWMODrawingBatch']
# control
mesh_type: int = ElementTypes.M2Mesh
shader: gpu.types.GPUShader
bl_batch_vert_shader_id: int
bl_batch_frag_shader_id: int
# uniform data
draw_material: Union['M2DrawingMaterial', 'WMODrawingMaterial', None]
# texture slots
gl_texture_slots = (
GL_TEXTURE0,
GL_TEXTURE1,
GL_TEXTURE2,
GL_TEXTURE3
)
def __init__(self
, c_batch: Union['CM2DrawingBatch', 'CWMODrawingBatch']
, draw_obj: Union['M2DrawingObject', 'WMODrawingObject']
, context: bpy.types.Context):
self.c_batch = c_batch
self.context = context
self.draw_obj = draw_obj
self.tag_free = False
self.mat_id = self.c_batch.get_mat_id()
try:
self.draw_material = self.draw_obj.draw_mgr.draw_materials.get(
self.draw_obj.bl_obj.data.materials[self.mat_id].name)
except IndexError:
self.draw_material = None
self.create_vao()
self.draw_obj.draw_mgr.draw_elements.add_batch(self)
render_debug('Instantiated drawing batch for object \"{}\"'.format(draw_obj.bl_obj.name))
@property
def is_transparent(self) -> bool:
return False
@property
def priority_plane(self) -> int:
return 0
@property
def layer(self) -> int:
return 0
@property
def is_skybox(self) -> bool:
return False
@property
def bb_center(self) -> mathutils.Vector:
raise NotImplementedError()
@property
def sort_radius(self) -> float:
return self.c_batch.sort_radius
@property
def sort_distance(self):
perspective_mat = self.draw_obj.draw_mgr.region_3d.perspective_matrix
bb_center = self.draw_obj.bl_obj.matrix_world @ self.bb_center
value = (perspective_mat.to_translation() - bb_center).length
if self.draw_material.is_inverted or self.draw_material.is_transformed:
result_point = bb_center * (1.0 / value) if value > 0.00000023841858 else bb_center
sort_dist = perspective_mat.to_translation().length * self.sort_radius
result_point *= sort_dist
value = (bb_center - result_point).length \
if self.draw_material.is_inverted else (bb_center + result_point).length
return value
def create_vao(self):
self.shader = self.determine_valid_shader()
self.c_batch.set_program(self.shader.program)
self.c_batch.create_vao()
glCheckError('Create VAO')
def ensure_context(self):
mat_test = self.draw_material.bl_material
if not mat_test:
self.tag_free = True
return self.tag_free
def _set_active_textures(self):
for i, gl_slot in enumerate(self.gl_texture_slots):
bind_code = self.draw_material.get_bindcode(i)
if bind_code:
glActiveTexture(gl_slot)
glBindTexture(GL_TEXTURE_2D, bind_code)
def determine_valid_shader(self) -> gpu.types.GPUShader:
raise NotImplementedError()
def draw(self):
render_debug('Drawing batch for object \"{}\"'.format(self.draw_obj.bl_obj.name))
bl_obj = self.draw_obj.bl_obj
if not bl_obj.visible_get():
return
if self.tag_free:
return
if self.draw_material:
self.draw_batch()
else:
self.draw_fallback()
def draw_fallback(self):
glCheckError('drawfallback pre')
self.shader = self.determine_valid_shader()
self.shader.bind()
self.c_batch.set_program(self.shader.program)
self.shader.uniform_float('uViewProjectionMatrix', self.draw_obj.draw_mgr.region_3d.perspective_matrix)
self.shader.uniform_float('uPlacementMatrix', self.draw_obj.bl_obj.matrix_world)
self.shader.uniform_float('uSunDirAndFogStart', self.draw_obj.draw_mgr.sun_dir_and_fog_start)
self.shader.uniform_float('uSunColorAndFogEnd', self.draw_obj.draw_mgr.sun_color_and_fog_end)
self.shader.uniform_float('uAmbientLight', self.draw_obj.draw_mgr.ambient_light)
self.shader.uniform_float('uFogColorAndAlphaTest', (*self.draw_obj.draw_mgr.fog_color, 1.0 / 255.0))
self.shader.uniform_int('UnFogged_IsAffectedByLight_LightCount', (False, True, 0))
glEnable(GL_DEPTH_TEST)
self.c_batch.draw()
glDisable(GL_DEPTH_TEST)
gpu.shader.unbind()
glCheckError('draw fallback post')
def draw_batch(self):
raise NotImplementedError()
def free(self):
if self.tag_free:
return
self.tag_free = True
self.draw_obj.draw_mgr.draw_elements.remove_batch(self)
@@ -0,0 +1,135 @@
import traceback
from enum import IntEnum
from copy import copy
from typing import List
from functools import cmp_to_key, partial
class ElementTypes(IntEnum):
GeneralMesh = 0
AdtMesh = 1
WmoMesh = 2
OccludingQuery = 3
M2Mesh = 4
ParticleMesh = 5
class DrawingElements:
def __init__(self):
self.batches: List['M2DrawingBatch'] = []
def add_batch(self, batch):
self.batches.append(batch)
def remove_batch(self, batch):
self.batches.remove(batch)
def draw(self):
batches = copy(self.batches)
try:
sorted_indices = sorted(list(range(len(self.batches))), key=cmp_to_key(partial(self.sort_elements, self)))
except IndexError:
print('Skipping frame! Iterator invalidated!')
self.draw()
#traceback.print_exc()
return
#print("Began drawing")
for batch_index in sorted_indices:
batch = batches[batch_index]
if batch.tag_free:
continue
try:
batch.draw()
#print(batch.draw_obj.bl_obj_name, batch.sort_distance)
except:
batch.free()
print('Debug: Freeing batch from DrawingElements!')
traceback.print_exc()
self.draw()
@staticmethod
def sort_elements(self, a, b):
batch_a = self.batches[a]
batch_b = self.batches[b]
#print("Comparing:", batch_a.draw_obj.bl_obj_name, batch_b.draw_obj.bl_obj_name)
if not batch_a.draw_material:
return -1
if not batch_b.draw_material:
return 1
if batch_a.is_transparent > batch_b.is_transparent:
return 1
if batch_a.is_transparent < batch_b.is_transparent:
return -1
if batch_a.mesh_type > batch_b.mesh_type:
return 1
if batch_a.mesh_type < batch_b.mesh_type:
return -1
if batch_a.is_skybox > batch_b.is_skybox:
return -1
if batch_a.is_skybox < batch_b.is_skybox:
return 1
if batch_a.mesh_type == ElementTypes.M2Mesh and batch_a.is_transparent and batch_b.is_transparent:
if batch_a.priority_plane != batch_b.priority_plane:
return -1 if batch_b.priority_plane > batch_a.priority_plane else 1
if batch_a.sort_distance > batch_b.sort_distance:
return -1
if batch_a.sort_distance < batch_b.sort_distance:
return 1
if batch_b.layer != batch_a.layer:
return -1 if batch_b.layer < batch_a.layer else 1
if batch_a.mesh_type == ElementTypes.ParticleMesh and batch_b.mesh_type == ElementTypes.ParticleMesh:
if batch_a.priority_plane != batch_b.priority_plane:
return -1 if batch_b.priority_plane > batch_a.priority_plane else 1
if batch_a.sort_distance > batch_b.sort_distance:
return -1
if batch_a.sort_distance < batch_b.sort_distance:
return 1
if batch_a.draw_material.blend_mode.index != batch_b.draw_material.blend_mode.index:
return -1 if batch_a.draw_material.blend_mode.index < batch_b.draw_material.blend_mode.index else 1
'''
min_tex_count = min(batch_a.texture_count, batch_b.texture_count)
for i in range(min_tex_count):
if batch_a.m_texture[i] != batch_b.m_texture[i]:
return batch_a.m_texture[i] < batch_b.m_texture[i]
if batch_a.texture_count != batch_b.texture_count:
return batch_a.texture_count < batch_b.texture_count
'''
"""
if batch_a.m_start != batch_b.m_start:
return batch_a.m_start < batch_b.m_start
if batch_a.m_end != batch_b.m_end:
return batch_a.m_end < batch_b.m_end
"""
return 1 if a > b else -1
@@ -0,0 +1,207 @@
import bpy
import gpu
import traceback
from typing import List, Tuple, Dict, Union
from mathutils import Vector
from .m2.shaders import M2ShaderPermutations
from .m2.drawing_object import M2DrawingObject
from .m2.drawing_material import M2DrawingMaterial
from .drawing_elements import DrawingElements
from .utils import render_debug
from .bgl_ext import glCheckError
from profilehooks import profile
from bgl import *
class DrawingManager:
sun_dir_and_fog_start: Tuple[float, float, float, float]
sun_color_and_fog_end: Tuple[float, float, float, float]
ambient_light: Tuple[float, float, float]
fog_color: Tuple[float, float, float]
def __init__(self, context):
glCheckError("draw mgr init pre")
self.context: bpy.types.Context = context
self.shaders = M2ShaderPermutations()
self.m2_objects: Dict[str, M2DrawingObject] = {}
self.draw_materials: Dict[str, M2DrawingMaterial] = {}
self.draw_elements = DrawingElements()
self.update_handlers = {'MESH': self._m2_handle_mesh_update}
self.is_dirty = True
self.editable_context = context.scene.wow_scene.type
# get active viewport
self.region_3d: bpy.types.SpaceView3D = bpy.context.space_data.region_3d
self.region: bpy.types.Region = self._get_active_region()
'''
# depth pass
self.depth_tex_id_buf = Buffer(GL_INT, 1)
glGenTextures(1, self.depth_tex_id_buf)
self.depth_tex_bindcode = self.depth_tex_id_buf.to_list()[0]
self.depth_buf = Buffer(GL_FLOAT, self.region.width * self.region.height)
'''
# uniform data
self._update_global_uniforms()
glCheckError("draw mgr init post")
render_debug('Instantiated drawing manager.')
def _update_global_uniforms(self):
sun_dir = Vector(self.context.scene.wow_render_settings.sun_direction)
sun_dir.negate()
self.sun_dir_and_fog_start = (*sun_dir[:3], self.context.scene.wow_render_settings.fog_start)
self.sun_color_and_fog_end = (*self.context.scene.wow_render_settings.ext_dir_color[:3],
self.context.scene.wow_render_settings.fog_end)
self.ambient_light = self.context.scene.wow_render_settings.ext_ambient_color
self.fog_color = self.context.scene.wow_render_settings.fog_color
@profile
def update_render_data(self, depsgraph: bpy.types.Depsgraph):
glCheckError("update render data pre")
try:
for update in depsgraph.updates:
if isinstance(update.id, bpy.types.Scene):
self._update_global_uniforms()
elif isinstance(update.id, bpy.types.Object) and update.is_updated_geometry:
update_handler = self.update_handlers.get(update.id.type)
if update_handler:
update_handler(depsgraph, update)
elif isinstance(update.id, bpy.types.Material):
render_debug('Detected update for material \"{}\"'.format(update.id.name))
draw_mat = self.draw_materials.get(update.id.name)
if draw_mat:
draw_mat.update_uniform_data()
else:
self.draw_materials[update.id.name] = M2DrawingMaterial(update.id.original)
# TODO: timer cleanup
except:
render_debug('Exception occured on depsgraph update of render data. Traceback is below.')
traceback.print_exc() # DEBUG
def init_datablocks(self, depsgraph: bpy.types.Depsgraph):
# init materials
for material in bpy.data.materials:
self.draw_materials[material.name] = M2DrawingMaterial(material)
for datablock in depsgraph.ids:
if isinstance(datablock, bpy.types.Scene):
self._update_global_uniforms()
elif isinstance(datablock, bpy.types.Object) and datablock.type == 'MESH':
self.m2_objects[datablock.name] = M2DrawingObject(datablock.original.evaluated_get(depsgraph), self, self.context)
def _m2_handle_mesh_update(self, depsgraph: bpy.types.Depsgraph, update: bpy.types.DepsgraphUpdate):
render_debug('Detected update for mesh \"{}\"'.format(update.id.name))
glCheckError("mesh update pre")
draw_obj = self.m2_objects.get(update.id.name)
if draw_obj:
draw_obj.update_geometry(update.id.original.evaluated_get(depsgraph))
else:
self.m2_objects[update.id.name] = M2DrawingObject(update.id.original.evaluated_get(depsgraph), self, self.context)
glCheckError("mesh update post")
@profile
def draw(self):
self.region_3d = bpy.context.space_data.region_3d
self.region = self._get_active_region()
for draw_obj in self.m2_objects.values():
if draw_obj.is_dirty:
draw_obj.update_geometry_opengl()
self.draw_elements.draw()
#self._render_depth_opengl()
#self.render_depth_texture()
#self._destroy_depthbuffer_texture()
def _linearize(self, depth):
znear = self.region_3d.clip_start
zfar = self.region_3d.clip_end
return (*([(-zfar * znear / (depth * (zfar - znear) - zfar)) / zfar] * 3), 1.0)
def render_depth_texture(self):
""" Render scene depth_tex_bindcode into texture """
width, height = self.region.width, self.region.height
image_name = "DepthBuffer"
if image_name not in bpy.data.images:
image = bpy.data.images.new(image_name, width, height)
else:
return
image.scale(width, height)
image.pixels = [y for x in [self._linearize(v) for v in self.depth_buf] for y in x]
@staticmethod
def _get_active_region() -> bpy.types.Region:
for region in bpy.context.area.regions:
if region.type == 'WINDOW':
return region
def _render_depth_opengl(self):
width, height = self.region.width, self.region.height
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, self.depth_tex_bindcode)
glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, self.depth_buf)
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height,
0, GL_DEPTH_COMPONENT, GL_FLOAT, self.depth_buf)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST)
glBindTexture(GL_TEXTURE_2D, self.depth_tex_bindcode)
return self.depth_tex_bindcode
def _destroy_depthbuffer_texture(self):
glDeleteTextures(1, self.depth_tex_id_buf)
@staticmethod
def _draw_callback(self):
self.draw()
def free(self):
for draw_obj in list(self.m2_objects.values()):
draw_obj.free()
render_debug('Freed drawing manager.')
@@ -0,0 +1,189 @@
import bpy
import bgl
from .drawing_manager import DrawingManager
from .utils import render_debug
from .bgl_ext import create_framebuffer, glCheckError
from ..wbs_kernel.render import OpenGLUtils
class WoWRenderEngine(bpy.types.RenderEngine):
# These three members are used by blender to set up the
# RenderEngine; define its internal name, visible name and capabilities.
bl_idname = "WOW"
bl_label = "WoW"
bl_use_preview = False
bl_use_eevee_viewport = True
# Init is called whenever a new render engine instance is created. Multiple
# instances may exist at the same time, for example for a viewport and final
# render.
def __init__(self):
self.glew_init = False
self.first_time = True
self.draw_manager = DrawingManager(bpy.context)
render_debug('Instantiated render engine.')
# When the render engine instance is destroy, this is called. Clean up any
# render engine data here, for example stopping running render threads.
def __del__(self):
render_debug('Freed render engine.')
# This is the method called by Blender for both final renders (F12) and
# small preview for materials, world and lights.
def render(self, depsgraph):
scene = depsgraph.scene
scale = scene.render.resolution_percentage / 100.0
self.size_x = int(scene.render.resolution_x * scale)
self.size_y = int(scene.render.resolution_y * scale)
# Fill the render result with a flat color. The framebuffer is
# defined as a list of pixels, each pixel itself being a list of
# R,G,B,A values.
if self.is_preview:
color = [0.1, 0.2, 0.1, 1.0]
else:
color = [0.2, 0.1, 0.1, 1.0]
pixel_count = self.size_x * self.size_y
rect = [color] * pixel_count
# Here we write the pixel values to the RenderResult
result = self.begin_result(0, 0, self.size_x, self.size_y)
layer = result.layers[0].passes["Combined"]
layer.rect = rect
self.end_result(result)
# For viewport renders, this method gets called once at the start and
# whenever the scene or 3D viewport changes. This method is where data
# should be read from Blender in the same thread. Typically a render
# thread will be started to do the work while keeping Blender responsive.
def view_update(self, context, depsgraph):
# depsgraph = context.evaluated_depsgraph_get()
if not self.glew_init:
OpenGLUtils.init_glew()
self.glew_init = True
region = context.region
view3d = context.space_data
scene = depsgraph.scene
# Get viewport dimensions
dimensions = region.width, region.height
if self.first_time:
self.first_time = False
self.draw_manager.init_datablocks(depsgraph)
else:
self.draw_manager.update_render_data(depsgraph)
'''
# Loop over all object instances in the scene.
if first_time or depsgraph.id_type_updated('OBJECT'):
for instance in depsgraph.object_instances:
pass
'''
render_debug('Num unfreed materials: {}\n'
'Num unfreed drawing objects: {}\n'
'Num unfreed batches: {}\n'.format(
len(self.draw_manager.draw_materials),
len(self.draw_manager.m2_objects),
len(self.draw_manager.draw_elements.batches))
)
# For viewport renders, this method is called whenever Blender redraws
# the 3D viewport. The renderer is expected to quickly draw the render
# with OpenGL, and not perform other expensive work.
# Blender will draw overlays for selection and editing on top of the
# rendered image automatically.
def view_draw(self, context, depsgraph):
# buf = bgl.Buffer(bgl.GL_INT, 1)
# bgl.glGetIntegerv(bgl.GL_FRAMEBUFFER_BINDING, buf)
# cur_fbo = buf.to_list()[0]
# del buf
#
# region = context.region
# view3d = context.space_data
# scene = depsgraph.scene
#
# # Get viewport dimensions
# width, height = region.width, region.height
#
# bgl.glBindFramebuffer(bgl.GL_FRAMEBUFFER, self.fbo_id)
#bgl.glEnable(bgl.GL_BLEND)
#bgl.glBlendFunc(bgl.GL_ONE, bgl.GL_ONE_MINUS_SRC_ALPHA)
#self.bind_display_space_shader(context.scene)
self.draw_manager.draw()
bgl.glColorMask(False, False, False, True)
bgl.glClearColor(0, 0, 0, 1.0)
bgl.glClear(bgl.GL_COLOR_BUFFER_BIT)
#self.unbind_display_space_shader()
#bgl.glDisable(bgl.GL_BLEND)
# glCheckError('post-draw-all')
#
# bgl.glBindFramebuffer(bgl.GL_DRAW_FRAMEBUFFER, cur_fbo)
# bgl.glDrawBuffer(bgl.GL_BACK)
#
# bgl.glBindFramebuffer(bgl.GL_READ_FRAMEBUFFER, self.fbo_id)
# bgl.glReadBuffer(bgl.GL_COLOR_ATTACHMENT0)
#
# glCheckError('bind fbos')
#
# bgl.glBlitFramebuffer(
# 0, 0, width, height,
# 0, 0, width, height,
# bgl.GL_COLOR_BUFFER_BIT | bgl.GL_DEPTH_BUFFER_BIT,
# bgl.GL_NEAREST)
#
# glCheckError('blit')
#
# bgl.glBindFramebuffer(bgl.GL_FRAMEBUFFER, cur_fbo)
# RenderEngines also need to tell UI Panels that they are compatible with.
# We recommend to enable all panels marked as BLENDER_RENDER, and then
# exclude any panels that are replaced by custom panels registered by the
# render engine, or that are not supported.
def get_panels():
exclude_panels = {
}
panels = []
for panel in bpy.types.Panel.__subclasses__():
if hasattr(panel, 'COMPAT_ENGINES'): # and 'BLENDER_RENDER' in panel.COMPAT_ENGINES:
if panel.__name__ not in exclude_panels:
panels.append(panel)
return panels
""" def register():
# Register the RenderEngine
bpy.utils.register_class(WoWRenderEngine)
for panel in get_panels():
panel.COMPAT_ENGINES.add('WOW')
def unregister():
bpy.utils.unregister_class(WoWRenderEngine)
for panel in get_panels():
if 'WOW' in panel.COMPAT_ENGINES:
panel.COMPAT_ENGINES.remove('WOW')
if __name__ == "__main__":
register() """
@@ -0,0 +1,203 @@
import bpy
import gpu
import mathutils
from typing import Union
from bgl import *
from ..drawing_batch import DrawingBatch
from ...wbs_kernel.render import CM2DrawingBatch
from ...wbs_kernel.render import OpenGLUtils
from .shaders import M2ShaderPermutations, EGxBLend
from .drawing_material import M2DrawingMaterial
from ..drawing_elements import ElementTypes
from ..utils import render_debug
from ..bgl_ext import glCheckError
class M2DrawingBatch(DrawingBatch):
c_batch: CM2DrawingBatch
# control
mesh_type: int = ElementTypes.M2Mesh
shader: gpu.types.GPUShader
bl_batch_vert_shader_id: int
bl_batch_frag_shader_id: int
gl_texture_slots = (
GL_TEXTURE0,
GL_TEXTURE1,
GL_TEXTURE2,
GL_TEXTURE3
)
# uniform data
draw_material: Union[M2DrawingMaterial, None]
def __init__(self
, c_batch: 'CM2DrawingBatch'
, draw_obj: 'M2DrawingObject'
, context: bpy.types.Context):
self.c_batch = c_batch
self.context = context
self.draw_obj = draw_obj
self.tag_free = False
self.mat_id = self.c_batch.get_mat_id()
try:
self.draw_material = self.draw_obj.draw_mgr.draw_materials.get(
self.draw_obj.bl_obj.data.materials[self.mat_id].name)
except IndexError:
self.draw_material = None
self.create_vao()
self.draw_obj.draw_mgr.draw_elements.add_batch(self)
render_debug('Instantiated drawing batch for object \"{}\"'.format(draw_obj.bl_obj.name))
@property
def is_transparent(self) -> bool:
return (self.draw_material.blend_mode.index > EGxBLend.AlphaKey.index) \
or not self.draw_material.depth_write
@property
def priority_plane(self) -> int:
return self.draw_material.bl_material.wow_m2_material.priority_plane
@property
def layer(self) -> int:
return self.draw_material.bl_material.wow_m2_material.layer
@property
def is_skybox(self) -> bool:
return self.draw_obj.is_skybox
@property
def bb_center(self) -> mathutils.Vector:
return mathutils.Vector(self.c_batch.bb_center)
@property
def sort_radius(self) -> float:
return self.c_batch.sort_radius
def determine_valid_shader(self) -> gpu.types.GPUShader:
shaders = M2ShaderPermutations()
if self.draw_material:
self.bl_batch_vert_shader_id = int(self.draw_material.bl_material.wow_m2_material.vertex_shader)
self.bl_batch_frag_shader_id = int(self.draw_material.bl_material.wow_m2_material.fragment_shader)
return shaders.get_shader_by_id(self.bl_batch_vert_shader_id,
self.bl_batch_frag_shader_id)
else:
return shaders.default_shader
def draw_batch(self):
glCheckError('draw')
#render_debug('Drawing batch for object \"{}\"'.format(self.draw_obj.bl_obj.name))
color_name = self.draw_material.bl_material.wow_m2_material.color
transparency_name = self.draw_material.bl_material.wow_m2_material.transparency
color = self.context.scene.wow_m2_colors[color_name].color if color_name else (1.0, 1.0, 1.0, 1.0)
if transparency_name:
transparency_rec = self.context.scene.wow_m2_transparency.get(transparency_name)
transparency = transparency_rec.value if transparency_rec else 1.0
else:
transparency = 1.0
combined_color = (*color[:3], color[3] * transparency)
u_alpha_test = 128.0 / 255.0 * combined_color[3] \
if self.draw_material.blend_mode.index == EGxBLend.AlphaKey.index else 1.0 / 255.0 # Maybe move this to shader logic?
self._set_active_textures()
self.shader = self.determine_valid_shader()
self.shader.bind()
glCheckError('Pre-link program')
self.c_batch.set_program(self.shader.program)
glCheckError('Post-link program')
# draw
if self.draw_material.depth_culling:
glEnable(GL_DEPTH_TEST)
glDepthMask(GL_TRUE if self.draw_material.depth_write else GL_FALSE)
if self.draw_material.backface_culling:
glEnable(GL_CULL_FACE)
if self.draw_material.blend_mode.blending_enabled:
glEnable(GL_BLEND)
if self.is_skybox:
glDepthRange(0.998, 1.0)
glBlendFunc(self.draw_material.blend_mode.src_color, self.draw_material.blend_mode.dest_color)
# OpenGLUtils.glBlendFuncSeparate(self.draw_material.blend_mode.src_color,
# self.draw_material.blend_mode.dest_color,
# self.draw_material.blend_mode.src_alpha,
# self.draw_material.blend_mode.dest_alpha)
self.shader.uniform_float('uViewProjectionMatrix', self.draw_obj.draw_mgr.region_3d.perspective_matrix)
self.shader.uniform_float('uPlacementMatrix', self.draw_obj.bl_obj.matrix_world)
self.shader.uniform_float('uSunDirAndFogStart', self.draw_obj.draw_mgr.sun_dir_and_fog_start)
self.shader.uniform_float('uSunColorAndFogEnd', self.draw_obj.draw_mgr.sun_color_and_fog_end)
self.shader.uniform_float('uAmbientLight', self.draw_obj.draw_mgr.ambient_light)
self.shader.uniform_float('uFogColorAndAlphaTest', (*self.draw_obj.draw_mgr.fog_color, u_alpha_test))
self.shader.uniform_int('UnFogged_IsAffectedByLight_LightCount', (self.draw_material.is_unfogged,
not self.draw_material.is_unlit, 0))
try:
self.shader.uniform_int('uTexture', 0)
except ValueError:
pass
try:
self.shader.uniform_int('uTexture2', 1)
except ValueError:
pass
try:
self.shader.uniform_int('uTexture3', 2)
except ValueError:
pass
try:
self.shader.uniform_int('uTexture4', 3)
except ValueError:
pass
self.shader.uniform_float('color_Transparency', combined_color)
self.c_batch.draw()
if self.is_skybox:
glDepthRange(0, 0.996)
if self.draw_material.blend_mode.blending_enabled:
glDisable(GL_BLEND)
if self.draw_material.backface_culling:
glDisable(GL_CULL_FACE)
glDepthMask(GL_FALSE if self.draw_material.depth_write else GL_TRUE)
if self.draw_material.depth_culling:
glDisable(GL_DEPTH_TEST)
gpu.shader.unbind()
glCheckError('draw end')
@@ -0,0 +1,87 @@
import bpy
from .shaders import EGxBlendRecord, M2BlendingModeToEGxBlend
class M2DrawingMaterial:
__slots__ = (
'draw_mgr',
'bl_material_name',
'blend_mode',
'depth_write',
'depth_culling',
'backface_culling',
'is_unlit',
'is_unfogged',
'is_inverted',
'is_transformed',
)
blend_mode: EGxBlendRecord
depth_write: bool
depth_culling: bool
backface_culling: bool
is_unlit: bool
is_unfogged: bool
is_inverted: bool
is_transformed: bool
def __init__(self, material: bpy.types.Material):
self.bl_material_name = material.name
self.update_uniform_data()
@property
def bl_material(self):
try:
return bpy.data.materials[self.bl_material_name]
except KeyError:
return None
def get_texture(self, tex_index: int):
mat = self.bl_material
if mat:
return getattr(mat.wow_m2_material, 'texture_{}'.format(tex_index + 1))
@property
def texture_count(self):
mat = self.bl_material
counter = 0
if mat:
for i in range(4):
tex = getattr(mat.wow_m2_material, 'texture_{}'.format(i + 1))
if tex:
counter += 1
return counter
def update_uniform_data(self):
bl_material = self.bl_material
if not bl_material:
return
self.blend_mode = M2BlendingModeToEGxBlend[int(self.bl_material.wow_m2_material.blending_mode)]
self.depth_write = '16' not in bl_material.wow_m2_material.render_flags
self.depth_culling = '8' not in bl_material.wow_m2_material.render_flags
self.backface_culling = '4' not in bl_material.wow_m2_material.render_flags
self.is_unlit = '1' in bl_material.wow_m2_material.render_flags
self.is_unfogged = '2' in bl_material.wow_m2_material.render_flags
self.is_inverted = '1' in bl_material.wow_m2_material.flags
self.is_transformed = '2' in bl_material.wow_m2_material.flags
def get_bindcode(self, tex_index: int) -> int:
texture = self.get_texture(tex_index)
if texture:
if not texture.bindcode:
texture.gl_load()
return texture.bindcode
return 0
@@ -0,0 +1,108 @@
import traceback
import bpy
import numpy as np
from mathutils import Matrix
from typing import List
from .drawing_batch import M2DrawingBatch
from ..utils import render_debug
from ...wbs_kernel.render import CM2DrawingMesh, CM2DrawingBatch
from ..bgl_ext import glCheckError
class M2DrawingObject:
batches: List[CM2DrawingBatch]
def __init__(self
, bl_obj: bpy.types.Object
, drawing_mgr: 'M2DrawingManager'
, context: bpy.types.Context
, is_skybox: bool = False):
self.context = context
self.draw_mgr = drawing_mgr
self.bl_obj_name = bl_obj.name
self.is_skybox = is_skybox
self.is_dirty = True
self.is_batching_valid = False
self.mesh_ptr = bl_obj.data.as_pointer()
self.c_mesh = CM2DrawingMesh(self.mesh_ptr)
self.batches = []
bl_obj.data.calc_loop_triangles()
render_debug('Initialized drawing object \"{}\"'.format(self.bl_obj_name))
self.update_geometry()
def update_geometry(self, bl_obj: bpy.types.Object = None):
if bl_obj:
self.c_mesh.update_mesh_pointer(bl_obj.data.as_pointer())
bl_obj.data.calc_loop_triangles()
self.is_batching_valid = self.c_mesh.update_geometry(not(self.context.screen.is_animation_playing or self.bl_obj.mode != 'OBJECT'))
self.is_dirty = True
def update_geometry_opengl(self, bl_obj: bpy.types.Object = None):
self.c_mesh.update_buffers()
if not self.is_batching_valid:
for batch in self.batches:
batch.free()
self.batches = \
[M2DrawingBatch(c_batch, self, self.context) for c_batch in self.c_mesh.get_drawing_batches()]
self.is_dirty = False
@property
def bl_obj(self):
try:
return bpy.data.objects[self.bl_obj_name]
except KeyError:
self.free()
def free(self):
for batch in self.batches:
batch.free()
del self.draw_mgr.m2_objects[self.bl_obj_name]
render_debug('Freed drawing object \"{}\"'.format(self.bl_obj_name))
'''
def update_bone_matrices(self):
rig = self.bl_rig
for i, pbone in enumerate(rig.pose.bones):
self.bone_matrices[i] = [j[i] for i in range(4) for j in pbone.matrix_channel]
def create_batches_from_armature(self, rig: bpy.types.Object):
for obj in filter(lambda x: x.type == 'MESH', rig.children):
# Limit bone influences to 4. TODO: rework to be non-destructive!
"""
if obj.vertex_groups:
active_obj = bpy.context.view_layer.objects.active
bpy.context.view_layer.objects.active = obj
bpy.ops.object.vertex_group_limit_total()
bpy.context.view_layer.objects.active = active_obj
"""
self.create_batch_from_object(obj)
def create_batch_from_object(self, obj: bpy.types.Object):
self.batches[obj.name] = M2DrawingBatch(obj, self, self.context)
'''
@@ -0,0 +1,319 @@
import os
import gpu
from enum import IntEnum
from ctypes import c_uint, c_uint8
from collections import namedtuple
from typing import Dict, Tuple
from ...utils.misc import singleton, Sequence
from ..shaders import ShaderPermutationsManager
from bgl import *
class M2PixelShader(IntEnum):
# Wotlk deprecated shaders
'''
Combiners_Decal = -1
Combiners_Add = -2
Combiners_Mod2x = -3
Combiners_Fade = -4,
Combiners_Opaque_Add = -5
Combiners_Opaque_AddNA = -6
Combiners_Add_Mod = -7
Combiners_Mod2x_Mod2x = -8
'''
# Legion modern shaders
Combiners_Opaque = 0
Combiners_Mod = 1
Combiners_Opaque_Mod = 2
Combiners_Opaque_Mod2x = 3
Combiners_Opaque_Mod2xNA = 4
Combiners_Opaque_Opaque = 5
Combiners_Mod_Mod = 6
Combiners_Mod_Mod2x = 7
Combiners_Mod_Add = 8
Combiners_Mod_Mod2xNA = 9
Combiners_Mod_AddNA = 10
Combiners_Mod_Opaque = 11
Combiners_Opaque_Mod2xNA_Alpha = 12
Combiners_Opaque_AddAlpha = 13
Combiners_Opaque_AddAlpha_Alpha = 14
Combiners_Opaque_Mod2xNA_Alpha_Add = 15
Combiners_Mod_AddAlpha = 16
Combiners_Mod_AddAlpha_Alpha = 17
Combiners_Opaque_Alpha_Alpha = 18
Combiners_Opaque_Mod2xNA_Alpha_3s = 19
Combiners_Opaque_AddAlpha_Wgt = 20
Combiners_Mod_Add_Alpha = 21
Combiners_Opaque_ModNA_Alpha = 22
Combiners_Mod_AddAlpha_Wgt = 23
Combiners_Opaque_Mod_Add_Wgt = 24
Combiners_Opaque_Mod2xNA_Alpha_UnshAlpha = 25
Combiners_Mod_Dual_Crossfade = 26
Combiners_Opaque_Mod2xNA_Alpha_Alpha = 27
Combiners_Mod_Masked_Dual_Crossfade = 28
Combiners_Opaque_Alpha = 29
Guild = 30
Guild_NoBorder = 31
Guild_Opaque = 32
Combiners_Mod_Depth = 33
Illum = 34
Combiners_Mod_Mod_Mod_Const = 35
class M2VertexShader(IntEnum):
Diffuse_T1 = 0
Diffuse_Env = 1
Diffuse_T1_T2 = 2
Diffuse_T1_Env = 3
Diffuse_Env_T1 = 4
Diffuse_Env_Env = 5
Diffuse_T1_Env_T1 = 6
Diffuse_T1_T1 = 7
Diffuse_T1_T1_T1 = 8
Diffuse_EdgeFade_T1 = 9
Diffuse_T2 = 10
Diffuse_T1_Env_T2 = 11
Diffuse_EdgeFade_T1_T2 = 12
Diffuse_EdgeFade_Env = 13
Diffuse_T1_T2_T1 = 14
Diffuse_T1_T2_T3 = 15
Color_T1_T2_T3 = 16
BW_Diffuse_T1 = 17
BW_Diffuse_T1_T2 = 18
EGxBlendRecord = namedtuple('EGxBlendRecord',
['blending_enabled', 'src_color', 'dest_color', 'src_alpha', 'dest_alpha', 'index'])
class EGxBLend(metaclass=Sequence):
Opaque = EGxBlendRecord(False, GL_ONE, GL_ZERO, GL_ONE, GL_ZERO, 0)
AlphaKey = EGxBlendRecord(False, GL_ONE, GL_ZERO, GL_ONE, GL_ZERO, 1)
Alpha = EGxBlendRecord(True, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, 2)
Add = EGxBlendRecord(True, GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE, 3)
Mod = EGxBlendRecord(True, GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO, 4)
Mod2x = EGxBlendRecord(True, GL_DST_COLOR, GL_SRC_COLOR, GL_DST_ALPHA, GL_SRC_ALPHA, 5)
ModAdd = EGxBlendRecord(True, GL_DST_COLOR, GL_ONE, GL_DST_ALPHA, GL_ONE, 6)
InvSrcAlphaAdd = EGxBlendRecord(True, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, 7)
InvSrcAlphaOpaque = EGxBlendRecord(True, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, 8)
SrcAlphaOpaque = EGxBlendRecord(True, GL_SRC_ALPHA, GL_ZERO, GL_SRC_ALPHA, GL_ZERO, 9)
NoAlphaAdd = EGxBlendRecord(True, GL_ONE, GL_ONE, GL_ZERO, GL_ONE, 10)
ConstantAlpha = EGxBlendRecord(True, GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA, GL_CONSTANT_ALPHA,
GL_ONE_MINUS_CONSTANT_ALPHA, 11)
Screen = EGxBlendRecord(True, GL_ONE_MINUS_DST_COLOR, GL_ONE, GL_ONE, GL_ZERO, 12)
BlendAdd = EGxBlendRecord(True, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, 13)
class M2BlendingModeToEGxBlend(metaclass=Sequence):
Blend_Opaque = EGxBLend.Opaque
Blend_AlphaKey = EGxBLend.AlphaKey
Blend_Alpha = EGxBLend.Alpha
Blend_NoAlphaAdd = EGxBLend.NoAlphaAdd
Blend_Add = EGxBLend.Add
Blend_Mod = EGxBLend.Mod
Blend_Mod2x = EGxBLend.Mod2x
Blend_BlendAdd = EGxBLend.BlendAdd
M2ShaderTableRecord = namedtuple('M2ShaderTableRecord', ['pixel_shader', 'vertex_shader'])
class M2ShaderTable(metaclass=Sequence):
Combiners_Opaque_Mod2xNA_Alpha_Diffuse_T1_Env = M2ShaderTableRecord(
M2PixelShader.Combiners_Opaque_Mod2xNA_Alpha, M2VertexShader.Diffuse_T1_Env)
Combiners_Opaque_AddAlpha_Diffuse_T1_Env = M2ShaderTableRecord(
M2PixelShader.Combiners_Opaque_AddAlpha, M2VertexShader.Diffuse_T1_Env)
Combiners_Opaque_AddAlpha_Alpha_Diffuse_T1_Env = M2ShaderTableRecord(
M2PixelShader.Combiners_Opaque_AddAlpha_Alpha, M2VertexShader.Diffuse_T1_Env)
Combiners_Opaque_Mod2xNA_Alpha_Add_Diffuse_T1_Env_T1 = M2ShaderTableRecord(
M2PixelShader.Combiners_Opaque_Mod2xNA_Alpha_Add, M2VertexShader.Diffuse_T1_Env_T1)
Combiners_Mod_AddAlpha_Diffuse_T1_Env = M2ShaderTableRecord(
M2PixelShader.Combiners_Mod_AddAlpha, M2VertexShader.Diffuse_T1_Env)
Combiners_Opaque_AddAlpha_Diffuse_T1_T1 = M2ShaderTableRecord(
M2PixelShader.Combiners_Opaque_AddAlpha, M2VertexShader.Diffuse_T1_T1)
Combiners_Mod_AddAlpha_Diffuse_T1_T1 = M2ShaderTableRecord(
M2PixelShader.Combiners_Mod_AddAlpha, M2VertexShader.Diffuse_T1_T1)
Combiners_Mod_AddAlpha_Alpha_Diffuse_T1_Env = M2ShaderTableRecord(
M2PixelShader.Combiners_Mod_AddAlpha_Alpha, M2VertexShader.Diffuse_T1_Env)
Combiners_Opaque_Alpha_Alpha_Diffuse_T1_Env = M2ShaderTableRecord(
M2PixelShader.Combiners_Opaque_Alpha_Alpha, M2VertexShader.Diffuse_T1_Env)
Combiners_Opaque_Mod2xNA_Alpha_3s_Diffuse_T1_Env_T1 = M2ShaderTableRecord(
M2PixelShader.Combiners_Opaque_Mod2xNA_Alpha_3s, M2VertexShader.Diffuse_T1_Env_T1)
Combiners_Opaque_AddAlpha_Wgt_Diffuse_T1_T1 = M2ShaderTableRecord(
M2PixelShader.Combiners_Opaque_AddAlpha_Wgt, M2VertexShader.Diffuse_T1_T1)
Combiners_Mod_Add_Alpha_Diffuse_T1_Env = M2ShaderTableRecord(
M2PixelShader.Combiners_Mod_Add_Alpha, M2VertexShader.Diffuse_T1_Env)
Combiners_Opaque_ModNA_Alpha_Diffuse_T1_Env = M2ShaderTableRecord(
M2PixelShader.Combiners_Opaque_ModNA_Alpha, M2VertexShader.Diffuse_T1_Env)
Combiners_Mod_AddAlpha_Wgt_Diffuse_T1_Env = M2ShaderTableRecord(
M2PixelShader.Combiners_Mod_AddAlpha_Wgt, M2VertexShader.Diffuse_T1_Env)
Combiners_Mod_AddAlpha_Wgt_Diffuse_T1_T1 = M2ShaderTableRecord(
M2PixelShader.Combiners_Mod_AddAlpha_Wgt, M2VertexShader.Diffuse_T1_T1)
Combiners_Opaque_AddAlpha_Wgt_Diffuse_T1_T2 = M2ShaderTableRecord(
M2PixelShader.Combiners_Opaque_AddAlpha_Wgt, M2VertexShader.Diffuse_T1_T2)
Combiners_Opaque_Mod_Add_Wgt_Diffuse_T1_Env = M2ShaderTableRecord(
M2PixelShader.Combiners_Opaque_Mod_Add_Wgt, M2VertexShader.Diffuse_T1_Env)
Combiners_Opaque_Mod2xNA_Alpha_UnshAlpha1 = M2ShaderTableRecord(
M2PixelShader.Combiners_Opaque_Mod2xNA_Alpha_UnshAlpha, M2VertexShader.Diffuse_T1_Env_T1)
Combiners_Mod_Dual_Crossfade_Diffuse_T1 = M2ShaderTableRecord(
M2PixelShader.Combiners_Mod_Dual_Crossfade, M2VertexShader.Diffuse_T1)
Combiners_Mod_Depth_Diffuse_EdgeFade_T1 = M2ShaderTableRecord(
M2PixelShader.Combiners_Mod_Depth, M2VertexShader.Diffuse_EdgeFade_T1)
Combiners_Opaque_Mod2xNA_Alpha_Alpha_Diffuse_T1_Env_T2 = M2ShaderTableRecord(
M2PixelShader.Combiners_Opaque_Mod2xNA_Alpha_Alpha, M2VertexShader.Diffuse_T1_Env_T2)
Combiners_Mod_Mod_Diffuse_EdgeFade_T1_T2 = M2ShaderTableRecord(
M2PixelShader.Combiners_Mod_Mod, M2VertexShader.Diffuse_EdgeFade_T1_T2)
Combiners_Mod_Masked_Dual_Crossfade_Diffuse_T1_T2 = M2ShaderTableRecord(
M2PixelShader.Combiners_Mod_Masked_Dual_Crossfade, M2VertexShader.Diffuse_T1_T2)
Combiners_Opaque_Alpha_Diffuse_T1_T1 = M2ShaderTableRecord(
M2PixelShader.Combiners_Opaque_Alpha, M2VertexShader.Diffuse_T1_T1)
Combiners_Opaque_Mod2xNA_Alpha_UnshAlpha2 = M2ShaderTableRecord(
M2PixelShader.Combiners_Opaque_Mod2xNA_Alpha_UnshAlpha, M2VertexShader.Diffuse_T1_Env_T2)
Combiners_Mod_Depth_Diffuse_EdgeFade_Env = M2ShaderTableRecord(
M2PixelShader.Combiners_Mod_Depth, M2VertexShader.Diffuse_EdgeFade_Env)
Guild_Diffuse_T1_T2_T1 = M2ShaderTableRecord(
M2PixelShader.Guild, M2VertexShader.Diffuse_T1_T2_T1)
Guild_NoBorder_Diffuse_T1_T2 = M2ShaderTableRecord(
M2PixelShader.Guild_NoBorder, M2VertexShader.Diffuse_T1_T2)
Guild_Opaque_Diffuse_T1_T2_T1 = M2ShaderTableRecord(
M2PixelShader.Guild_Opaque, M2VertexShader.Diffuse_T1_T2_T1)
Illum_Diffuse_T1_T1 = M2ShaderTableRecord(
M2PixelShader.Illum, M2VertexShader.Diffuse_T1_T1)
Combiners_Mod_Mod_Mod_Const_Diffuse_T1_T2_T3 = M2ShaderTableRecord(
M2PixelShader.Combiners_Mod_Mod_Mod_Const, M2VertexShader.Diffuse_T1_T2_T3)
Combiners_Mod_Mod_Mod_Const_Color_T1_T2_T3 = M2ShaderTableRecord(
M2PixelShader.Combiners_Mod_Mod_Mod_Const, M2VertexShader.Color_T1_T2_T3)
Combiners_Opaque_Diffuse_T1 = M2ShaderTableRecord(
M2PixelShader.Combiners_Opaque, M2VertexShader.Diffuse_T1)
Combiners_Mod_Mod2x_Diffuse_EdgeFade_T1_T2 = M2ShaderTableRecord(
M2PixelShader.Combiners_Mod_Mod2x, M2VertexShader.Diffuse_EdgeFade_T1_T2)
@singleton
class M2ShaderPermutations(ShaderPermutationsManager):
shader_source_path = 'm2_shader'
@staticmethod
def get_vertex_shader_id(texture_count: int, shader_id: int) -> int:
if shader_id < 0: # all shaders with negative shader id
vertex_shader_id = shader_id & 0x7FFF
if c_uint(vertex_shader_id).value >= 0x22:
raise ValueError("Wrong shader ID for vertex shader")
result = c_uint(M2ShaderTable[vertex_shader_id].vertex_shader).value
# reverse: vertex_shader_id | 0x80000000 for int32) (do with ctypes)
elif texture_count == 1: # 0, 1, 10
if (shader_id & 0x80) != 0:
result = 1
else:
result = 10
if not (shader_id & 0x4000):
result = 0
elif (shader_id & 0x80) != 0: # 4, 5
result = ((shader_id & 8) >> 3) | 4
else: # 3, 7, 8
result = 3
if not (shader_id & 8):
result = 5 * c_uint((shader_id & 0x4000) == 0).value + 2
return result
@staticmethod
def get_pixel_shader_id(texture_count: int, shader_id: int):
array1 = [
M2PixelShader.Combiners_Mod_Mod2x,
M2PixelShader.Combiners_Mod_Mod,
M2PixelShader.Combiners_Mod_Mod2xNA,
M2PixelShader.Combiners_Mod_AddNA,
M2PixelShader.Combiners_Mod_Opaque,
M2PixelShader.Combiners_Mod_Mod,
M2PixelShader.Combiners_Mod_Mod,
M2PixelShader.Combiners_Mod_Add
]
array2 = [
M2PixelShader.Combiners_Opaque_Mod2x,
M2PixelShader.Combiners_Opaque_Mod,
M2PixelShader.Combiners_Opaque_Mod2xNA,
M2PixelShader.Combiners_Opaque_AddAlpha_Alpha,
M2PixelShader.Combiners_Opaque_Opaque,
M2PixelShader.Combiners_Opaque_Mod,
M2PixelShader.Combiners_Opaque_Mod,
M2PixelShader.Combiners_Opaque_AddAlpha_Alpha
]
if shader_id < 0: # all shaders with negative shader id
pixel_shader_id = shader_id & 0x7FFF
if c_uint(pixel_shader_id).value >= 0x22:
raise ValueError("Wrong shader ID for pixel shader")
result = c_uint(M2ShaderTable[pixel_shader_id].pixel_shader).value
# reverse: pixel_shader_id | 0x80000000 for int32) (do with ctypes)
elif texture_count == 1: # 0, 1
result = int((shader_id & 0x70) != 0)
else:
cur_array = array2
if shader_id & 0x70:
cur_array = array1
result = cur_array[(c_uint8(shader_id).value ^ 4) & 7].value
return result
@staticmethod
def get_shader_combo_index(vertex_shader_id: int, pixel_shader_id: int):
for record in M2ShaderTable:
if record.value.vertex_shader == vertex_shader_id and record.value.pixel_shader == pixel_shader_id:
return record.index
@@ -0,0 +1,68 @@
import os
import gpu
from typing import Tuple, Dict, Any
from ..utils.misc import singleton, Sequence
class ShaderPermutationsFormat:
M2 = 0,
WMO = 1,
ADT = 2
class ShaderPermutationsManager:
shader_source_path: str
extra_defines: Dict[str, Any]
def __init__(self):
self.shader_permutations: Dict = {}
self.shader_source: str
self.default_shader: gpu.types.GPUShader
rel_path = 'shaders\\glsl330\\{}.glsl'.format(self.shader_source_path) if os.name == 'nt'\
else 'shaders/glsl330/{}.glsl'.format(self.shader_source_path)
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), rel_path)) as f:
self.shader_source = "".join(f.readlines())
rel_path = 'shaders\\glsl330\\default.glsl' if os.name == 'nt' else 'shaders/glsl330/default.glsl'
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), rel_path)) as f:
shader_source_fallback = "".join(f.readlines())
vert_shader_string_perm = "#define COMPILING_VS {}\n" \
"{}".format(1, shader_source_fallback)
frag_shader_string_perm = "#define COMPILING_FS {}\n" \
"{}".format(1, shader_source_fallback)
self.default_shader = gpu.types.GPUShader(vert_shader_string_perm, frag_shader_string_perm)
def _compile_shader_permutation(self
, vert_shader_id: int
, frag_shader_id: int) -> gpu.types.GPUShader:
vert_shader_string_perm = "#define COMPILING_VS {}\n" \
"#define VERTEXSHADER {}\n" \
"{}".format(1, vert_shader_id, self.shader_source)
frag_shader_string_perm = "#define COMPILING_FS {}\n" \
"#define FRAGMENTSHADER {}\n" \
"{}".format(1, frag_shader_id, self.shader_source)
shader = gpu.types.GPUShader(vert_shader_string_perm, frag_shader_string_perm)
self.shader_permutations[vert_shader_id, frag_shader_id] = shader
return shader
def get_shader_by_id(self
, vert_shader_id: int
, frag_shader_id: int) -> gpu.types.GPUShader:
shader = self.shader_permutations.get((vert_shader_id, frag_shader_id))
if not shader:
shader = self._compile_shader_permutation(vert_shader_id, frag_shader_id)
return shader
@@ -0,0 +1,198 @@
#ifdef COMPILING_VS
/* vertex shader code */
in vec3 aPosition;
in vec3 aNormal;
// Whole model
uniform mat4 uViewProjectionMatrix;
uniform mat4 uPlacementMatrix;
//Individual meshes
uniform vec4 color_Transparency;
//Shader output
out vec3 vPosition;
out vec3 vNormal;
void main() {
vec4 aPositionVec4 = vec4(aPosition, 1.0f);
mat3 viewModelMatTransposed = mat3(uViewProjectionMatrix);
mat4 cameraMatrix = uViewProjectionMatrix;
vec4 cameraPoint = cameraMatrix * (uPlacementMatrix * aPositionVec4);
vec3 normal = normalize(viewModelMatTransposed * (mat3(uPlacementMatrix) * aNormal));
vNormal = normal;
vPosition = cameraPoint.xyz;
gl_Position = cameraPoint;
}
#endif //COMPILING_VS
#ifdef COMPILING_FS
struct LocalLight
{
vec4 color;
vec4 position;
vec4 attenuation;
};
in vec3 vPosition;
in vec3 vNormal;
out vec4 outputColor;
//Whole model
uniform mat4 uViewProjectionMatrix;
uniform vec4 uSunDirAndFogStart;
uniform vec4 uSunColorAndFogEnd;
uniform vec4 uAmbientLight;
uniform ivec3 UnFogged_IsAffectedByLight_LightCount;
uniform vec4 uFogColorAndAlphaTest;
uniform LocalLight pc_lights[4];
vec3 makeDiffTerm(vec3 matDiffuse, vec3 accumLight) {
vec3 currColor;
float mult = 1.0;
vec3 lDiffuse = vec3(0.0, 0.0, 0.0);
vec4 viewUp = uViewProjectionMatrix * vec4(0, 0, 1, 0);
if (UnFogged_IsAffectedByLight_LightCount.y == 1) {
vec3 normalizedN = normalize(vNormal);
float nDotL = clamp(dot(normalizedN, -(uSunDirAndFogStart.xyz)), 0.0, 1.0);
float nDotUp = dot(normalizedN, viewUp.xyz);
vec4 AmbientLight = uAmbientLight;
vec3 adjAmbient = (AmbientLight.rgb );
vec3 adjHorizAmbient = (AmbientLight.rgb );
vec3 adjGroundAmbient = (AmbientLight.rgb );
if ((nDotUp >= 0.0))
{
currColor = mix(adjHorizAmbient, adjAmbient, vec3(nDotUp));
}
else
{
currColor= mix(adjHorizAmbient, adjGroundAmbient, vec3(-(nDotUp)));
}
vec3 skyColor = (currColor * 1.10000002);
vec3 groundColor = (currColor* 0.699999988);
lDiffuse = (uSunColorAndFogEnd.xyz * nDotL);
currColor = mix(groundColor, skyColor, vec3((0.5 + (0.5 * nDotL))));
} else {
currColor = vec3 (1.0, 1.0, 1.0) ;
accumLight = vec3(0,0,0);
mult = 1.0;
}
vec3 gammaDiffTerm = matDiffuse * (currColor + lDiffuse);
vec3 linearDiffTerm = (matDiffuse * matDiffuse) * accumLight;
return sqrt(gammaDiffTerm*gammaDiffTerm + linearDiffTerm) ;
}
void main() {
vec4 finalColor = vec4(0);
vec4 meshResColor = vec4(0.5, 0.5, 0.5, 1.0);
vec4 vDiffuseColor = meshResColor;
vec3 accumLight;
if ((UnFogged_IsAffectedByLight_LightCount.y == 1)) {
vec3 vPos3 = vPosition.xyz;
vec3 vNormal3 = normalize(vNormal.xyz);
vec3 lightColor = vec3(0.0);
int count = int(pc_lights[0].attenuation.w);
int index = 0;
for (;;)
{
if ( index >= UnFogged_IsAffectedByLight_LightCount.z) break;
LocalLight lightRecord = pc_lights[index];
vec3 vectorToLight = ((lightRecord.position).xyz - vPos3);
float distanceToLightSqr = dot(vectorToLight, vectorToLight);
float distanceToLightInv = inversesqrt(distanceToLightSqr);
float distanceToLight = (distanceToLightSqr * distanceToLightInv);
float diffuseTerm1 = max((dot(vectorToLight, vNormal3) * distanceToLightInv), 0.0);
vec4 attenuationRec = lightRecord.attenuation;
float attenuation = (1.0 - clamp((distanceToLight - attenuationRec.x) * (1.0 / (attenuationRec.z - attenuationRec.x)), 0.0, 1.0));
vec3 attenuatedColor = attenuation * lightRecord.color.xyz * attenuationRec.y;
lightColor = (lightColor + vec3(attenuatedColor * attenuatedColor * diffuseTerm1 ));
index++;
}
meshResColor.rgb = clamp(lightColor , 0.0, 1.0);
accumLight = meshResColor.rgb;
//finalColor.rgb = finalColor.rgb * lightColor;
}
float opacity;
float finalOpacity = 0.0;
vec3 matDiffuse;
vec3 specular = vec3(0.0, 0.0, 0.0);
vec3 visParams = vec3(1.0, 1.0, 1.0);
vec4 genericParams[3];
genericParams[0] = vec4( 1.0, 1.0, 1.0, 1.0 );
genericParams[1] = vec4( 1.0, 1.0, 1.0, 1.0 );
genericParams[2] = vec4( 1.0, 1.0, 1.0, 1.0 );
//Combiners_Opaque
matDiffuse = vDiffuseColor.rgb * 2.000000;
opacity = vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
finalColor = vec4(makeDiffTerm(matDiffuse, accumLight) + specular, finalOpacity);
int uUnFogged = UnFogged_IsAffectedByLight_LightCount.x;
float uFogEnd = uSunColorAndFogEnd.w;
if (uUnFogged == 0) {
vec3 fogColor = uFogColorAndAlphaTest.xyz;
float fog_rate = 1.5;
float fog_bias = 0.01;
//vec4 fogHeightPlane = pc_fog.heightPlane;
//float heightRate = pc_fog.color_and_heightRate.w;
float distanceToCamera = length(vPosition.xyz);
float z_depth = (distanceToCamera - fog_bias);
float expFog = 1.0 / (exp((max(0.0, (z_depth - uSunDirAndFogStart.w)) * fog_rate)));
//float height = (dot(fogHeightPlane.xyz, vPosition.xyz) + fogHeightPlane.w);
//float heightFog = clamp((height * heightRate), 0, 1);
float heightFog = 1.0;
expFog = (expFog + heightFog);
float endFadeFog = clamp(((uFogEnd - distanceToCamera) / (0.699999988 * uFogEnd)), 0.0, 1.0);
float fog_out = min(expFog, endFadeFog);
finalColor.rgba = vec4(mix(fogColor.rgb, finalColor.rgb, vec3(fog_out)), finalColor.a);
}
//outputColor = blender_srgb_to_framebuffer_space(finalColor);
finalColor.a = clamp(finalColor.a, 0.0, 1.0);
outputColor = vec4(finalColor.rgb, finalColor.a);
}
#endif //COMPILING_FS
@@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://dm7a4pi3f0j31"
path="res://.godot/imported/default.glsl-3ffe109a58103ff0ad40364a19be71ef.res"
[deps]
source_file="res://reference/blender-wow-studio-3.4-1.1.0_Experimental/io_scene_wmo/render/shaders/glsl330/default.glsl"
dest_files=["res://.godot/imported/default.glsl-3ffe109a58103ff0ad40364a19be71ef.res"]
[params]
@@ -0,0 +1,574 @@
// Library code
vec2 posToTexCoord(vec3 cameraPoint, vec3 normal){
// vec3 normPos = -normalize(cameraPoint.xyz);
// vec3 normPos = cameraPoint.xyz;
// vec3 reflection = reflect(normPos, normal);
// return (normalize(vec3(reflection.r, reflection.g, reflection.b + 1.0)).rg * 0.5) + vec2(0.5);
vec3 normPos_495 = normalize(cameraPoint.xyz);
vec3 temp_500 = (normPos_495 - (normal * (2.0 * dot(normPos_495, normal))));
vec3 temp_657 = vec3(temp_500.x, temp_500.y, (temp_500.z + 1.0));
return ((normalize(temp_657).xy * 0.5) + vec2(0.5));
}
float edgeScan(vec3 position, vec3 normal){
float dotProductClamped = clamp(dot(-normalize(position),normal), 0.000000, 1.000000);
return clamp(2.700000 * dotProductClamped * dotProductClamped - 0.400000, 0.000000, 1.000000);
}
mat3 blizzTranspose(mat4 value) {
return mat3(
value[0].xyz,
value[1].xyz,
value[2].xyz
);
}
// Shader code
#ifdef COMPILING_VS
precision highp float;
/* vertex shader code */
in vec3 aPosition;
in vec3 aNormal;
in vec2 aTexCoord;
in vec2 aTexCoord2;
// Whole model
uniform mat4 uViewProjectionMatrix;
uniform mat4 uPlacementMatrix;
//Individual meshes
uniform vec4 color_Transparency;
//Shader output
out vec3 vPosition;
out vec3 vNormal;
out vec2 vTexCoord;
out vec2 vTexCoord2;
out vec2 vTexCoord3;
out vec4 vDiffuseColor;
void main() {
vec4 aPositionVec4 = vec4(aPosition, 1.0f);
vec4 lDiffuseColor = color_Transparency;
vec4 combinedColor = clamp(lDiffuseColor /*+ vc_matEmissive*/, 0.000000, 1.000000);
vec4 combinedColorHalved = combinedColor * 0.5;
mat3 viewModelMatTransposed = mat3(uViewProjectionMatrix);
mat4 cameraMatrix = uViewProjectionMatrix;
vec4 cameraPoint = cameraMatrix * (uPlacementMatrix * aPositionVec4);
// Handle normals
vec3 normal = normalize(viewModelMatTransposed * (mat3(uPlacementMatrix) * aNormal));
vec2 envCoord = posToTexCoord(cameraPoint.xyz, normal);
float edgeScanVal = edgeScan(cameraPoint.xyz, normal);
// Handle colors and texture coordinates
vTexCoord2 = vec2(0.0);
vTexCoord3 = vec2(0.0);
//Diffuse_T1
#if VERTEXSHADER == 0
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
vTexCoord = aTexCoord;
#endif
//Diffuse_Env
#if VERTEXSHADER == 1
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
vTexCoord = envCoord;
#endif
//Diffuse_T1_T2
#if VERTEXSHADER == 2
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
vTexCoord = aTexCoord;
vTexCoord2 = aTexCoord2;
#endif
#if VERTEXSHADER == 3 //Diffuse_T1_Env
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
vTexCoord = aTexCoord;
vTexCoord2 = envCoord;
#endif
#if VERTEXSHADER == 4 //Diffuse_Env_T1
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
vTexCoord = envCoord;
vTexCoord2 = aTexCoord;
#endif
#if VERTEXSHADER == 5 //Diffuse_Env_Env
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
vTexCoord = envCoord;
vTexCoord2 = envCoord;
#endif
#if VERTEXSHADER == 6 //Diffuse_T1_Env_T1
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
vTexCoord = aTexCoord;
vTexCoord2 = envCoord;
vTexCoord3 = aTexCoord;
#endif
#if VERTEXSHADER == 7 //Diffuse_T1_T1
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
vTexCoord = aTexCoord;
vTexCoord2 = aTexCoord;
#endif
#if VERTEXSHADER == 8 //Diffuse_T1_T1_T1
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
vTexCoord = aTexCoord;
vTexCoord2 = aTexCoord;
vTexCoord3 = aTexCoord;
#endif
#if VERTEXSHADER == 9 //Diffuse_EdgeFade_T1+
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a * edgeScanVal);
vTexCoord = aTexCoord;
#endif
#if VERTEXSHADER == 10 //Diffuse_T2
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
vTexCoord = aTexCoord2;
#endif
#if VERTEXSHADER == 11 //Diffuse_T1_Env_T2
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
vTexCoord = aTexCoord;
vTexCoord2 = envCoord;
vTexCoord3 = aTexCoord2;
#endif
#if VERTEXSHADER == 12 //Diffuse_EdgeFade_T1_T2
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a * edgeScanVal);
vTexCoord = aTexCoord;
vTexCoord2 = aTexCoord2;
#endif
#if VERTEXSHADER == 13 //Diffuse_EdgeFade_Env
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a * edgeScanVal);
vTexCoord = envCoord;
#endif
#if VERTEXSHADER == 14 //Diffuse_T1_T2_T1
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
vTexCoord = aTexCoord;
vTexCoord2 = aTexCoord2;
vTexCoord3 = aTexCoord;
#endif
#if VERTEXSHADER == 15 //Diffuse_T1_T2_T3
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
vTexCoord = aTexCoord;
vTexCoord2 = aTexCoord2;
vTexCoord3 = vTexCoord3;
#endif
#if VERTEXSHADER == 16 //Color_T1_T2_T3
vec4 in_col0 = vec4(1.0, 1.0, 1.0, 1.0);
vDiffuseColor = vec4((in_col0.rgb * 0.500000).r, (in_col0.rgb * 0.500000).g, (in_col0.rgb * 0.500000).b, in_col0.a);
vTexCoord = aTexCoord2;
vTexCoord2 = vec2(0.000000, 0.000000);
vTexCoord3 = vTexCoord3;
#endif
#if VERTEXSHADER == 17 //BW_Diffuse_T1
vDiffuseColor = vec4(combinedColor.rgb * 0.500000, combinedColor.a);
vTexCoord = aTexCoord;
#endif
#if VERTEXSHADER == 18 //BW_Diffuse_T1_T2
vDiffuseColor = vec4(combinedColor.rgb * 0.500000, combinedColor.a);
vTexCoord = aTexCoord;
#endif
vNormal = normal;
vPosition = cameraPoint.xyz;
gl_Position = cameraPoint;
}
#endif //COMPILING_VS
#ifdef COMPILING_FS
precision highp float;
struct LocalLight
{
vec4 color;
vec4 position;
vec4 attenuation;
};
in vec3 vNormal;
in vec2 vTexCoord;
in vec2 vTexCoord2;
in vec2 vTexCoord3;
in vec3 vPosition;
in vec4 vDiffuseColor;
uniform sampler2D uTexture;
uniform sampler2D uTexture2;
uniform sampler2D uTexture3;
uniform sampler2D uTexture4;
out vec4 outputColor;
//Whole model
uniform mat4 uViewProjectionMatrix;
uniform vec4 uSunDirAndFogStart;
uniform vec4 uSunColorAndFogEnd;
uniform vec4 uAmbientLight;
uniform ivec3 UnFogged_IsAffectedByLight_LightCount;
uniform vec4 uFogColorAndAlphaTest;
uniform LocalLight pc_lights[4];
vec3 makeDiffTerm(vec3 matDiffuse, vec3 accumLight) {
vec3 currColor;
float mult = 1.0;
vec3 lDiffuse = vec3(0.0, 0.0, 0.0);
vec4 viewUp = uViewProjectionMatrix * vec4(0, 0, 1, 0);
if (UnFogged_IsAffectedByLight_LightCount.y == 1) {
vec3 normalizedN = normalize(vNormal);
float nDotL = clamp(dot(normalizedN, -(uSunDirAndFogStart.xyz)), 0.0, 1.0);
float nDotUp = dot(normalizedN, viewUp.xyz);
vec4 AmbientLight = uAmbientLight;
vec3 adjAmbient = (AmbientLight.rgb );
vec3 adjHorizAmbient = (AmbientLight.rgb );
vec3 adjGroundAmbient = (AmbientLight.rgb );
if ((nDotUp >= 0.0))
{
currColor = mix(adjHorizAmbient, adjAmbient, vec3(nDotUp));
}
else
{
currColor= mix(adjHorizAmbient, adjGroundAmbient, vec3(-(nDotUp)));
}
vec3 skyColor = (currColor * 1.10000002);
vec3 groundColor = (currColor* 0.699999988);
lDiffuse = (uSunColorAndFogEnd.xyz * nDotL);
currColor = mix(groundColor, skyColor, vec3((0.5 + (0.5 * nDotL))));
} else {
currColor = vec3 (1.0, 1.0, 1.0) ;
accumLight = vec3(0,0,0);
mult = 1.0;
}
vec3 gammaDiffTerm = matDiffuse * (currColor + lDiffuse);
vec3 linearDiffTerm = (matDiffuse * matDiffuse) * accumLight;
return sqrt(gammaDiffTerm*gammaDiffTerm + linearDiffTerm) ;
}
void main() {
/* Animation support */
vec2 texCoord = vTexCoord.xy;
vec2 texCoord2 = vTexCoord2.xy;
vec2 texCoord3 = vTexCoord3.xy;
vec3 gamma = vec3(0.454);
/* Get color from texture */
vec4 tex = texture(uTexture, texCoord).rgba;
//tex = vec4(pow(tex.rgb, gamma), tex.a);
vec4 tex2 = texture(uTexture2, texCoord2).rgba;
//tex2 = vec4(pow(tex2.rgb, gamma), tex2.a);
vec4 tex3 = texture(uTexture3, texCoord3).rgba;
//tex3 = vec4(pow(tex3.rgb, gamma), tex3.a);
vec4 tex2WithTextCoord1 = texture(uTexture2,texCoord);
vec4 tex3WithTextCoord1 = texture(uTexture3,texCoord);
vec4 tex4WithTextCoord2 = texture(uTexture4,texCoord2);
vec4 finalColor = vec4(0);
vec4 meshResColor = vDiffuseColor;
vec3 accumLight;
if ((UnFogged_IsAffectedByLight_LightCount.y == 1))
{
vec3 vPos3 = vPosition.xyz;
vec3 vNormal3 = normalize(vNormal.xyz);
vec3 lightColor = vec3(0.0);
int count = int(pc_lights[0].attenuation.w);
int index = 0;
for (;;)
{
if ( index >= UnFogged_IsAffectedByLight_LightCount.z) break;
LocalLight lightRecord = pc_lights[index];
vec3 vectorToLight = ((lightRecord.position).xyz - vPos3);
float distanceToLightSqr = dot(vectorToLight, vectorToLight);
float distanceToLightInv = inversesqrt(distanceToLightSqr);
float distanceToLight = (distanceToLightSqr * distanceToLightInv);
float diffuseTerm1 = max((dot(vectorToLight, vNormal3) * distanceToLightInv), 0.0);
vec4 attenuationRec = lightRecord.attenuation;
float attenuation = (1.0 - clamp((distanceToLight - attenuationRec.x) * (1.0 / (attenuationRec.z - attenuationRec.x)), 0.0, 1.0));
vec3 attenuatedColor = attenuation * lightRecord.color.xyz * attenuationRec.y;
lightColor = (lightColor + vec3(attenuatedColor * attenuatedColor * diffuseTerm1 ));
index++;
}
meshResColor.rgb = clamp(lightColor , 0.0, 1.0);
accumLight = meshResColor.rgb;
//finalColor.rgb = finalColor.rgb * lightColor;
}
float opacity;
float finalOpacity = 0.0;
vec3 matDiffuse;
vec3 specular = vec3(0.0, 0.0, 0.0);
vec3 visParams = vec3(1.0, 1.0, 1.0);
vec4 genericParams[3];
genericParams[0] = vec4( 1.0, 1.0, 1.0, 1.0 );
genericParams[1] = vec4( 1.0, 1.0, 1.0, 1.0 );
genericParams[2] = vec4( 1.0, 1.0, 1.0, 1.0 );
#if(FRAGMENTSHADER==0) //Combiners_Opaque
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
opacity = vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==1) //Combiners_Mod
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
opacity = tex.a * vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==2) //Combiners_Opaque_Mod
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * tex2.rgb;
opacity = tex2.a * vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==3) //Combiners_Opaque_Mod2x
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * tex2.rgb * 2.000000;
opacity = tex2.a * 2.000000 * vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==4) //Combiners_Opaque_Mod2xNA
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * tex2.rgb * 2.000000;
opacity = vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==5) //Combiners_Opaque_Opaque
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * tex2.rgb;
opacity = vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==6) //Combiners_Mod_Mod
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * tex2.rgb;
opacity = tex.a * tex2.a * vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==7) //Combiners_Mod_Mod2x
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * tex2.rgb * 2.000000;
opacity = tex.a * tex2.a * 2.000000 * vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==8) //Combiners_Mod_Add
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
opacity = (tex.a + tex2.a) * vDiffuseColor.a;
specular = tex2.rgb;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==9) //Combiners_Mod_Mod2xNA
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * tex2.rgb * 2.000000;
opacity = tex.a * vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==10) //Combiners_Mod_AddNA
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
opacity = tex.a * vDiffuseColor.a;
specular = tex2.rgb;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==11) //Combiners_Mod_Opaque
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * tex2.rgb;
opacity = tex.a * vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==12) //Combiners_Opaque_Mod2xNA_Alpha
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb * tex2.rgb * 2.000000, tex.rgb, vec3(tex.a));
opacity = vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==13) //Combiners_Opaque_AddAlpha
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
specular = tex2.rgb * tex2.a;
opacity = vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==14) //Combiners_Opaque_AddAlpha_Alpha
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
specular = tex2.rgb * tex2.a * (1.000000 - tex.a);
opacity = vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==15) //Combiners_Opaque_Mod2xNA_Alpha_Add
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb * tex2.rgb * 2.000000, tex.rgb, vec3(tex.a));
specular = tex3.rgb * tex3.a * genericParams[0].b;
opacity = vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==16) //Combiners_Mod_AddAlpha
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
opacity = tex.a * vDiffuseColor.a;
specular = tex2.rgb * tex2.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==17) //Combiners_Mod_AddAlpha_Alpha
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
opacity = (tex.a + tex2.a * (0.300000 * tex2.r + 0.590000 * tex2.g + 0.110000 * tex2.b)) * vDiffuseColor.a;
specular = tex2.rgb * tex2.a * (1.000000 - tex.a);
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==18) //Combiners_Opaque_Alpha_Alpha
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(mix(tex.rgb, tex2.rgb, vec3(tex2.a)), tex.rgb, vec3(tex.a));
opacity = vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==19) //Combiners_Opaque_Mod2xNA_Alpha_3s
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb * tex2.rgb * 2.000000, tex3.rgb, vec3(tex3.a));
opacity = vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==20) //Combiners_Opaque_AddAlpha_Wgt
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
specular = tex2.rgb * tex2.a * genericParams[0].g;
opacity = vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==21) //Combiners_Mod_Add_Alpha
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
opacity = (tex.a + tex2.a) * vDiffuseColor.a;
specular = tex2.rgb * (1.000000 - tex.a);
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==22) //Combiners_Opaque_ModNA_Alpha
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb * tex2.rgb, tex.rgb, vec3(tex.a));
opacity = vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==23) //Combiners_Mod_AddAlpha_Wgt
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
opacity = tex.a * vDiffuseColor.a;
specular = tex2.rgb * tex2.a * genericParams[0].g;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==24) //Combiners_Opaque_Mod_Add_Wgt
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb, tex2.rgb, vec3(tex2.a));
specular = tex.rgb * tex.a * genericParams[0].r;
opacity = vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==25) //Combiners_Opaque_Mod2xNA_Alpha_UnshAlpha
float glowOpacity = clamp((tex3.a * genericParams[0].z), 0.0, 1.0);
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb * tex2.rgb * 2.000000, tex.rgb, vec3(tex.a)) * (1.000000 - glowOpacity);
specular = tex3.rgb * glowOpacity;
opacity = vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==26) //Combiners_Mod_Dual_Crossfade
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(mix(tex, tex2WithTextCoord1, vec4(clamp(genericParams[0].g, 0.000000, 1.000000))), tex3WithTextCoord1, vec4(clamp(genericParams[0].b, 0.000000, 1.000000))).rgb;
opacity = mix(mix(tex, tex2WithTextCoord1, vec4(clamp(genericParams[0].g, 0.000000, 1.000000))), tex3WithTextCoord1, vec4(clamp(genericParams[0].b, 0.000000, 1.000000))).a * vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==27) //Combiners_Opaque_Mod2xNA_Alpha_Alpha
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(mix(tex.rgb * tex2.rgb * 2.000000, tex3.rgb, vec3(tex3.a)), tex.rgb, vec3(tex.a));
opacity = vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==28) //Combiners_Mod_Masked_Dual_Crossfade
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(mix(tex, tex2WithTextCoord1, vec4(clamp(genericParams[0].g, 0.000000, 1.000000))), tex3WithTextCoord1, vec4(clamp(genericParams[0].b, 0.000000, 1.000000))).rgb;
opacity = mix(mix(tex, tex2WithTextCoord1, vec4(clamp(genericParams[0].g, 0.000000, 1.000000))), tex3WithTextCoord1, vec4(clamp(genericParams[0].b, 0.000000, 1.000000))).a * tex4WithTextCoord2.a * vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==29) //Combiners_Opaque_Alpha
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb, tex2.rgb, vec3(tex2.a));
opacity = vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==30) //Guild
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb * mix(genericParams[0].rgb, tex2.rgb * genericParams[1].rgb, vec3(tex2.a)), tex3.rgb * genericParams[2].rgb, vec3(tex3.a));
opacity = tex.a * vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==31) //Guild_NoBorder
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * mix(genericParams[0].rgb, tex2.rgb * genericParams[1].rgb, vec3(tex2.a));
opacity = tex.a * vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==32) //Guild_Opaque
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb * mix(genericParams[0].rgb, tex2.rgb * genericParams[1].rgb, vec3(tex2.a)), tex3.rgb * genericParams[2].rgb, vec3(tex3.a));
opacity = vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==33) //Combiners_Mod_Depth
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
opacity = tex.a * vDiffuseColor.a * visParams.r;
finalOpacity = opacity * visParams.r;
#endif
#if(FRAGMENTSHADER==34) //Illum
finalColor = vec4(1.0,1.0,1.0, 1.0);
//Unusued
#endif
#if(FRAGMENTSHADER==35) //Combiners_Mod_Mod_Mod_Const
matDiffuse = vDiffuseColor.rgb * 2.000000 * (tex * tex2 * tex3 * genericParams[0]).rgb;
opacity = (tex * tex2 * tex3 * genericParams[0]).a * vDiffuseColor.a;
finalOpacity = opacity * visParams.r;
#endif
finalColor = vec4(makeDiffTerm(matDiffuse, accumLight) + specular, finalOpacity);
if(finalColor.a < uFogColorAndAlphaTest.w)
discard;
int uUnFogged = UnFogged_IsAffectedByLight_LightCount.x;
float uFogEnd = uSunColorAndFogEnd.w;
if (uUnFogged == 0) {
vec3 fogColor = uFogColorAndAlphaTest.xyz;
float fog_rate = 1.5;
float fog_bias = 0.01;
//vec4 fogHeightPlane = pc_fog.heightPlane;
//float heightRate = pc_fog.color_and_heightRate.w;
float distanceToCamera = length(vPosition.xyz);
float z_depth = (distanceToCamera - fog_bias);
float expFog = 1.0 / (exp((max(0.0, (z_depth - uSunDirAndFogStart.w)) * fog_rate)));
//float height = (dot(fogHeightPlane.xyz, vPosition.xyz) + fogHeightPlane.w);
//float heightFog = clamp((height * heightRate), 0, 1);
float heightFog = 1.0;
expFog = (expFog + heightFog);
float endFadeFog = clamp(((uFogEnd - distanceToCamera) / (0.699999988 * uFogEnd)), 0.0, 1.0);
float fog_out = min(expFog, endFadeFog);
finalColor.rgba = vec4(mix(fogColor.rgb, finalColor.rgb, vec3(fog_out)), finalColor.a);
}
//outputColor = blender_srgb_to_framebuffer_space(finalColor);
finalColor.a = clamp(finalColor.a, 0.0, 1.0);
outputColor = vec4(finalColor.rgb, finalColor.a);
}
#endif //COMPILING_FS
@@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://ilf2tqewt1xj"
path="res://.godot/imported/m2_shader.glsl-f5a0cdc7b7a147950d5f7fe94dd0ed5e.res"
[deps]
source_file="res://reference/blender-wow-studio-3.4-1.1.0_Experimental/io_scene_wmo/render/shaders/glsl330/m2_shader.glsl"
dest_files=["res://.godot/imported/m2_shader.glsl-f5a0cdc7b7a147950d5f7fe94dd0ed5e.res"]
[params]
@@ -0,0 +1,407 @@
#ifdef COMPILING_VS
/* vertex shader code */
precision highp float;
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoord;
layout (location = 3) in vec2 aTexCoord2;
layout (location = 4) in vec2 aTexCoord3;
layout (location = 5) in vec4 aColor;
layout (location = 6) in vec4 aColor2;
uniform mat4 uViewProjectionMatrix;
uniform mat4 uPlacementMat;
uniform vec4 uAmbientBakedTerm; // color to subtract in FixColorVertexAlpha, see CMapObjGroup::FixColorVertexAlpha(CMapObjGroup *mapObjGroup)
out vec2 vTexCoord;
out vec2 vTexCoord2;
out vec2 vTexCoord3;
out vec4 vColor;
out vec4 vColor2;
out vec4 vPosition;
out vec3 vNormal;
// trans batch
#if(BATCH_TYPE==0)
#if(DO_NOT_FIX_ALPHA==1)
vec4 FixColorVertexAlpha(vec4 vertexColor)
{
return vertexColor;
}
#else
vec4 FixColorVertexAlpha(vec4 vertexColor)
{
vec4 vertexColor = aColor;
vertexColor.b -= uAmbientBakedTerm.b;
vertexColor.g -= uAmbientBakedTerm.g;
vertexColor.r -= uAmbientBakedTerm.r;
float alpha_factor = mccv.a;
vertexColor.b = (vertexColor.b - alpha_factor * vertexColor.b) / 2;
vertexColor.g = (vertexColor.g - alpha_factor * vertexColor.g) / 2;
vertexColor.r = (vertexColor.r - alpha_factor * vertexColor.r) / 2;
return vertexColor;
}
#endif
#endif
// int batch
#if(BATCH_TYPE==1 || BATCH_TYPE==2)
#if(DO_NOT_FIX_ALPHA==1)
vec4 FixColorVertexAlpha(vec4 vertexColor)
{
vec4 vertexColor = aColor;
#if(EXTERIOR==1)
vertexColor.a = 255;
#else
vertexColor.a = 0;
#endif
return vertexColor;
}
#else
vec4 FixColorVertexAlpha(vec4 vertexColor)
{
vec4 vertexColor = aColor;
float new_b = (vertexColor.b * vertexColor.a) / 0.25 + vertexColor.b - uAmbientBakedTerm.b;
vertexColor.b = min (1.0, max(new_b / 2, 0));
float new_g = (vertexColor.g * vertexColor.a) / 0.25 + vertexColor.g - uAmbientBakedTerm.g;
vertexColor.g = min (1.0, max(new_g / 2, 0));
float new_r = (vertexColor.r * vertexColor.a) / 0.25 + vertexColor.r - uAmbientBakedTerm.r;
vertexColor.r = min (1.0, max(new_r / 2, 0));
#if(EXTERIOR==1)
vertexColor.a = 255;
#else
vertexColor.a = 0;
#endif
return vertexColor;
}
#endif
#endif
void main() {
vec4 worldPoint = uPlacementMat * vec4(aPosition, 1);
vec4 cameraPoint = uLookAtMat * worldPoint;
mat4 viewModelMat = uLookAtMat * uPlacementMat;
mat3 viewModelMatTransposed = mat3(
viewModelMat[0].xyz,
viewModelMat[1].xyz,
viewModelMat[2].xyz
);
gl_Position = cameraPoint.xyz;
vertexColor = FixColorVertexAlpha(aColor);
vPosition = vec4(cameraPoint.xyz, vertexColor.w);
vNormal = normalize(viewModelMatTransposed * aNormal);
vColor.rgba = vec4(vec3(0.5, 0.499989986, 0.5), 1.0);
vColor2 = vec4((vertexColor.rgb * 2.0), aColor2.a);
#if(VERTEXSHADER==-1)
vTexCoord = aTexCoord;
vTexCoord2 = aTexCoord2;
vTexCoord3 = aTexCoord3;
#endif
#if(VERTEXSHADER==0) //MapObjDiffuse_T1
vTexCoord = aTexCoord;
vTexCoord2 = aTexCoord2; //not used
vTexCoord3 = aTexCoord3; //not used
#endif
#if(VERTEXSHADER==1) //MapObjDiffuse_T1_Refl
vTexCoord = aTexCoord;
vTexCoord2 = reflect(normalize(cameraPoint.xyz), vNormal).xy;
vTexCoord3 = aTexCoord3; //not used
#endif
#if(VERTEXSHADER==2) //MapObjDiffuse_T1_Env_T2
vTexCoord = aTexCoord;
vTexCoord2 = posToTexCoord(vPosition.xyz, vNormal);;
vTexCoord3 = aTexCoord3;
#endif
#if(VERTEXSHADER==3) //MapObjSpecular_T1
vTexCoord = aTexCoord;
vTexCoord2 = aTexCoord2; //not used
vTexCoord3 = aTexCoord3; //not used
#endif
#if(VERTEXSHADER==4) //MapObjDiffuse_Comp
vTexCoord = aTexCoord;
vTexCoord2 = aTexCoord2; //not used
vTexCoord3 = aTexCoord3; //not used
#endif
#if(VERTEXSHADER==5) //MapObjDiffuse_Comp_Refl
vTexCoord = aTexCoord;
vTexCoord2 = aTexCoord2;
vTexCoord3 = reflect(normalize(cameraPoint.xyz), vNormal).xy;
#endif
#if(VERTEXSHADER==6) //MapObjDiffuse_Comp_Terrain
vTexCoord = aTexCoord;
vTexCoord2 = vPosition.xy * -0.239999995;
vTexCoord3 = aTexCoord3; //not used
#endif
#if(VERTEXSHADER==7) //MapObjDiffuse_CompAlpha
vTexCoord = aTexCoord;
vTexCoord2 = vPosition.xy * -0.239999995;
vTexCoord3 = aTexCoord3; //not used
#endif
#if(VERTEXSHADER==8) //MapObjParallax
vTexCoord = aTexCoord;
vTexCoord2 = vPosition.xy * -0.239999995;
vTexCoord3 = aTexCoord3; //not used
#endif
//
// vs_out.vTexCoord = vTexCoord;
// vs_out.vTexCoord2 = vTexCoord2;
// vs_out.vTexCoord3 = vTexCoord3;
// vs_out.vColor = vColor;
// vs_out.vColor2 = vColor2;
// vs_out.vPosition = vPosition;
// vs_out.vNormal = vNormal;
}
#endif //COMPILING_VS
#ifdef COMPILING_FS
precision highp float;
in vec2 vTexCoord;
in vec2 vTexCoord2;
in vec2 vTexCoord3;
in vec4 vColor;
in vec4 vColor2;
in vec4 vPosition;
in vec3 vNormal;
uniform vec4 uSunDir_FogStart;
uniform vec4 uSunColor_uFogEnd;
uniform vec4 uAmbientLight;
uniform vec4 uAmbientLight2AndIsBatchA;
uniform ivec4 UseLitColor_EnableAlpha_PixelShader;
uniform vec4 FogColor_AlphaTest;
uniform sampler2D uTexture;
uniform sampler2D uTexture2;
uniform sampler2D uTexture3;
layout (location = 0) out vec4 outputColor;
vec3 makeDiffTerm(vec3 matDiffuse) {
vec3 currColor;
vec3 lDiffuse = vec3(0.0, 0.0, 0.0);
vec4 viewUp = uViewProjectionMatrix * vec4(0, 0, 1, 0);
if (UseLitColor_EnableAlpha_PixelShader.x == 1) {
//vec3 viewUp = normalize(vec3(0, 0.9, 0.1));
vec3 normalizedN = normalize(vNormal);
float nDotL = dot(normalizedN, -(uSunDir_FogStart.xyz));
float nDotUp = dot(normalizedN, ViewUp.xyz);
vec3 precomputed = vColor2.rgb;
vec3 ambientColor = uAmbientLight.rgb;
if (uAmbientLight2AndIsBatchA.w > 0.0) {
ambientColor = mix(uAmbientLight.rgb, uAmbientLight2AndIsBatchA.rgb, vec3(vPosition.w));
}
vec3 adjAmbient = (ambientColor.rgb + precomputed);
vec3 adjHorizAmbient = (ambientColor.rgb + precomputed);
vec3 adjGroundAmbient = (ambientColor.rgb + precomputed);
if ((nDotUp >= 0.0))
{
currColor = mix(adjHorizAmbient, adjAmbient, vec3(nDotUp));
}
else
{
currColor= mix(adjHorizAmbient, adjGroundAmbient, vec3(-(nDotUp)));
}
vec3 skyColor = (currColor * 1.10000002);
vec3 groundColor = (currColor* 0.699999988);
currColor = mix(groundColor, skyColor, vec3((0.5 + (0.5 * nDotL))));
lDiffuse = (uSunColor_uFogEnd.xyz * clamp(nDotL, 0.0, 1.0));
} else {
currColor = vec3 (1.0, 1.0, 1.0) * uAmbientLight.rgb;
}
vec3 gammaDiffTerm = matDiffuse * (currColor + lDiffuse);
vec3 linearDiffTerm = (matDiffuse * matDiffuse) * vec3(0.0);
return sqrt(gammaDiffTerm*gammaDiffTerm + linearDiffTerm) ;
// return matDiffuse * currColor.rgb ;
}
void main() {
vec4 tex = texture(uTexture, vTexCoord).rgba ;
vec4 tex2 = texture(uTexture2, vTexCoord2).rgba;
vec4 tex3 = texture(uTexture3, vTexCoord3).rgba;
if (UseLitColor_EnableAlpha_PixelShader.y == 1) {
if ((tex.a - 0.501960814) < 0.0) {
discard;
}
}
int uPixelShader = UseLitColor_EnableAlpha_PixelShader.z;
vec4 finalColor = vec4(0.0, 0.0, 0.0, 1.0);
#if(FRAGMENTSHADER==-1)
finalColor = vec4(makeDiffTerm(tex.rgb * vColor.rgb + tex2.rgb*vColor2.bgr), tex.a);
#endif
#if(FRAGMENTSHADER==0) //MapObjDiffuse
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
#endif
#if(FRAGMENTSHADER==1) //MapObjSpecular
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
#endif
#if(FRAGMENTSHADER==2) //MapObjMetal
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
#endif
#if(FRAGMENTSHADER==3) //MapObjEnv
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
vec3 env = tex2.rgb * tex.a;
finalColor.rgba = vec4(makeDiffTerm(matDiffuse)+env, vColor.a);
#endif
#if(FRAGMENTSHADER==4) //MapObjOpaque
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
#endif
#if(FRAGMENTSHADER==5) //MapObjEnvMetal
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
vec3 env = (tex.rgb * tex.a) * tex2.rgb;
finalColor.rgba = vec4(makeDiffTerm(matDiffuse)+env, vColor.a);
#endif
#if(FRAGMENTSHADER==6) //MapObjTwoLayerDiffuse
vec3 layer1 = tex.rgb;
vec3 layer2 = mix(layer1, tex2.rgb, tex2.a);
vec3 matDiffuse = (vColor.rgb * 2.0) * mix(layer2, layer1, vColor2.a);
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), 1.0);
#endif
#if(FRAGMENTSHADER==7) //MapObjTwoLayerEnvMetal
vec4 colorMix = mix(tex2, tex, vColor2.a);
vec3 env = (colorMix.rgb * colorMix.a) * tex3.rgb;
vec3 matDiffuse = colorMix.rgb * (2.0 * vColor.rgb);
finalColor.rgba = vec4(makeDiffTerm(matDiffuse)+env, vColor.a);
#endif
#if(FRAGMENTSHADER==8) //MapObjTwoLayerTerrain
vec3 layer1 = tex.rgb;
vec3 layer2 = tex2.rgb;
vec3 matDiffuse = ((vColor.rgb * 2.0) * mix(layer2, layer1, vColor2.a));
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
#endif
#if(FRAGMENTSHADER==9) //MapObjDiffuseEmissive
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
vec3 env = tex2.rgb * tex2.a * vColor2.a;
finalColor.rgba = vec4(makeDiffTerm(matDiffuse)+env, vColor.a);
#endif
#if(FRAGMENTSHADER==10) //MapObjMaskedEnvMetal
float mixFactor = clamp((tex3.a * vColor2.a), 0.0, 1.0);
vec3 matDiffuse =
(vColor.rgb * 2.0) *
mix(mix(((tex.rgb * tex2.rgb) * 2.0), tex3.rgb, mixFactor), tex.rgb, tex.a);
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
#endif
#if(FRAGMENTSHADER==11) //MapObjEnvMetalEmissive
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
vec3 env =
(
((tex.rgb * tex.a) * tex2.rgb) +
((tex3.rgb * tex3.a) * vColor2.a)
);
finalColor.rgba = vec4(makeDiffTerm(matDiffuse)+env, vColor.a);
#endif
#if(FRAGMENTSHADER==12) //MapObjTwoLayerDiffuseOpaque
vec3 matDiffuse =
(vColor.rgb * 2.0) *
mix(tex2.rgb, tex.rgb, vColor2.a);
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
#endif
#if(FRAGMENTSHADER==13) //MapObjTwoLayerDiffuseEmissive
vec3 t1diffuse = (tex2.rgb * (1.0 - tex2.a));
vec3 matDiffuse =
((vColor.rgb * 2.0) *
mix(t1diffuse, tex.rgb, vColor2.a));
//TODO: there is env missing here
vec3 env = ((tex2.rgb * tex2.a) * (1.0 - vColor2.a));
finalColor.rgba = vec4(makeDiffTerm(matDiffuse)+env, vColor.a);
#endif
#if(FRAGMENTSHADER==14) //MapObjAdditiveMaskedEnvMetal
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
#endif
#if(FRAGMENTSHADER==15) //MapObjTwoLayerDiffuseMod2x
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
#endif
#if(FRAGMENTSHADER==16) //MapObjTwoLayerDiffuseMod2xNA
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
#endif
#if(FRAGMENTSHADER==17) //MapObjTwoLayerDiffuseAlpha
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
#endif
#if(FRAGMENTSHADER==18) //MapObjLod
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
#endif
#if(FRAGMENTSHADER==19) //MapObjParallax
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
#endif
//finalColor.rgb *= 4.0;
if(finalColor.a < FogColor_AlphaTest.w)
discard;
vec3 fogColor = FogColor_AlphaTest.xyz;
float fog_start = uSunDir_FogStart.w;
float fog_end = uSunColor_uFogEnd.w;
float fog_rate = 1.5;
float fog_bias = 0.01;
//vec4 fogHeightPlane = pc_fog.heightPlane;
//float heightRate = pc_fog.color_and_heightRate.w;
float distanceToCamera = length(vPosition.xyz);
float z_depth = (distanceToCamera - fog_bias);
float expFog = 1.0 / (exp((max(0.0, (z_depth - fog_start)) * fog_rate)));
//float height = (dot(fogHeightPlane.xyz, vPosition.xyz) + fogHeightPlane.w);
//float heightFog = clamp((height * heightRate), 0, 1);
float heightFog = 1.0;
expFog = (expFog + heightFog);
float endFadeFog = clamp(((fog_end - distanceToCamera) / (0.699999988 * fog_end)), 0.0, 1.0);
finalColor.rgb = mix(fogColor.rgb, finalColor.rgb, vec3(min(expFog, endFadeFog)));
finalColor.a = 1.0; //do I really need it now?
outputColor = finalColor;
}
#endif //COMPILING_FS
@@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://6u013f07jwx4"
path="res://.godot/imported/wmo_shader.glsl-c651a24623613dfab3d43adcd04efd4d.res"
[deps]
source_file="res://reference/blender-wow-studio-3.4-1.1.0_Experimental/io_scene_wmo/render/shaders/glsl330/wmo_shader.glsl"
dest_files=["res://.godot/imported/wmo_shader.glsl-c651a24623613dfab3d43adcd04efd4d.res"]
[params]
@@ -0,0 +1,260 @@
// M2
mathfu::vec3 &M2MeshBufferUpdater::getFogColor(EGxBlendEnum blendMode, mathfu::vec3 &originalFogColor) {
static mathfu::vec3 fog_zero = mathfu::vec3(0,0,0);
static mathfu::vec3 fog_half = mathfu::vec3(0.5,0.5,0.5);
static mathfu::vec3 fog_one = mathfu::vec3(1.0,1.0,1.0);
switch (blendMode) {
case EGxBlendEnum::GxBlend_Opaque: //Blend_Opaque
case EGxBlendEnum::GxBlend_AlphaKey : //Blend_AlphaKey
case EGxBlendEnum::GxBlend_Alpha : //Blend_Alpha
return originalFogColor;
case EGxBlendEnum::GxBlend_NoAlphaAdd : //Blend_NoAlphaAdd
case EGxBlendEnum::GxBlend_Add : //Blend_Add
return fog_zero;
case EGxBlendEnum::GxBlend_Mod: //Blend_Mod
return fog_one;
case EGxBlendEnum::GxBlend_Mod2x:
case EGxBlendEnum::GxBlend_BlendAdd:
return fog_half;
default :
debuglog("Unknown blending mode in M2 file")
break;
}
return originalFogColor;
}
void M2MeshBufferUpdater::fillLights(const M2Object &m2Object, meshWideBlockPS &meshblockPS) {
bool BCLoginScreenHack = m2Object.m_api->getConfig()->getBCLightHack();
int lightCount = (int) std::min(m2Object.lights.size(), (size_t) 4);
for (int j = 0; j < lightCount; j++) {
std::string uniformName;
mathfu::vec4 attenVec;
if (BCLoginScreenHack) {
attenVec = mathfu::vec4(m2Object.lights[j].attenuation_start, 1.0, m2Object.lights[j].attenuation_end, m2Object.lights.size());
} else {
// if ((lights[i].attenuation_end - lights[i].attenuation_start < 0.1)) continue;
// attenVec = mathfu::vec4(lights[i].attenuation_start, 1.0, lights[i].attenuation_end, lights.size());
attenVec = mathfu::vec4(m2Object.lights[j].attenuation_start, m2Object.lights[j].diffuse_intensity, m2Object.lights[j].attenuation_end, m2Object.lights.size());
}
meshblockPS.pc_lights[j].attenuation = attenVec;//;lights[i].diffuse_color);
meshblockPS.pc_lights[j].color = m2Object.lights[j].diffuse_color;
// mathfu::vec4 viewPos = modelView * m2Object.lights[j].position;
meshblockPS.pc_lights[j].position = m2Object.lights[j].position;
}
meshblockPS.LightCount = lightCount;
}
// sorting
void M2Object::sortMaterials(mathfu::mat4 &modelViewMat) {
if (!m_loaded) return;
M2Data * m2File = this->m_m2Geom->getM2Data();
M2SkinProfile * skinData = this->m_skinGeom->getSkinData();
for (int i = 0; i < this->m_meshArray.size(); i++) {
//Update info for sorting
M2MeshBufferUpdater::updateSortData(this->m_meshArray[i], *this, m_materialArray[i], m2File, skinData, modelViewMat);
}
}
void M2MeshBufferUpdater::updateSortData(HGM2Mesh &hmesh, const M2Object &m2Object, M2MaterialInst &materialData,
const M2Data * m2File, const M2SkinProfile *m2SkinProfile, mathfu::mat4 &modelViewMat) {
M2Batch *textMaterial = m2SkinProfile->batches.getElement(materialData.texUnitTexIndex);
M2SkinSection *submesh = m2SkinProfile->submeshes.getElement(textMaterial->skinSectionIndex);
mathfu::vec4 centerBB = mathfu::vec4(mathfu::vec3(submesh->sortCenterPosition), 1.0);
const mathfu::mat4 &boneMat = m2Object.bonesMatrices[submesh->centerBoneIndex];
centerBB = modelViewMat * (boneMat * centerBB);
float value = centerBB.xyz().Length();
if (textMaterial->flags & 3) {
mathfu::vec4 resultPoint;
if ( value > 0.00000023841858 ) {
resultPoint = centerBB * (1.0f / value);
} else {
resultPoint = centerBB;
}
mathfu::mat4 mat4 = modelViewMat * boneMat;
float dist = mat4.GetColumn(3).xyz().Length();
float sortDist = dist * submesh->sortRadius;
resultPoint *= sortDist;
if (textMaterial->flags & 1) {
value = (centerBB - resultPoint).xyz().Length();
} else {
value = (centerBB + resultPoint).xyz().Length();
}
}
hmesh->setSortDistance(value);
static inline bool sortMeshes(const HGMesh a, const HGMesh b) {
auto* pA = a.get();
auto* pB = b.get();
if (pA->getIsTransparent() > pB->getIsTransparent()) {
return false;
}
if (pA->getIsTransparent() < pB->getIsTransparent()) {
return true;
}
if (pA->getMeshType() > pB->getMeshType()) {
return false;
}
if (pA->getMeshType() < pB->getMeshType()) {
return true;
}
if (pA->m_renderOrder != pB->m_renderOrder ) {
if (!pA->getIsTransparent()) {
return pA->m_renderOrder < pB->m_renderOrder;
} else {
return pA->m_renderOrder > pB->m_renderOrder;
}
}
if (pA->m_isSkyBox > pB->m_isSkyBox) {
return true;
}
if (pA->m_isSkyBox < pB->m_isSkyBox) {
return false;
}
if (pA->getMeshType() == MeshType::eM2Mesh && pA->getIsTransparent() && pB->getIsTransparent()) {
if (pA->m_priorityPlane != pB->m_priorityPlane) {
return pB->m_priorityPlane > pA->m_priorityPlane;
}
if (pA->m_sortDistance > pB->m_sortDistance) {
return true;
}
if (pA->m_sortDistance < pB->m_sortDistance) {
return false;
}
if (pA->m_m2Object > pB->m_m2Object) {
return true;
}
if (pA->m_m2Object < pB->m_m2Object) {
return false;
}
if (pB->m_layer != pA->m_layer) {
return pB->m_layer < pA->m_layer;
}
}
if (pA->getMeshType() == MeshType::eParticleMesh && pB->getMeshType() == MeshType::eParticleMesh) {
if (pA->m_priorityPlane != pB->m_priorityPlane) {
return pB->m_priorityPlane > pA->m_priorityPlane;
}
if (pA->m_sortDistance > pB->m_sortDistance) {
return true;
}
if (pA->m_sortDistance < pB->m_sortDistance) {
return false;
}
}
if (pA->m_bindings != pB->m_bindings) {
return pA->m_bindings > pB->m_bindings;
}
if (pA->getGxBlendMode() != pB->getGxBlendMode()) {
return pA->getGxBlendMode() < pB->getGxBlendMode();
}
int minTextureCount = pA->m_textureCount < pB->m_textureCount ? pA->m_textureCount : pB->m_textureCount;
for (int i = 0; i < minTextureCount; i++) {
if (pA->m_texture[i] != pB->m_texture[i]) {
return pA->m_texture[i] < pB->m_texture[i];
}
}
if (pA->m_textureCount != pB->m_textureCount) {
return pA->m_textureCount < pB->m_textureCount;
}
if (pA->m_start != pB->m_start) {
return pA->m_start < pB->m_start;
}
if (pA->m_end != pB->m_end) {
return pA->m_end < pB->m_end;
}
return a > b;
}
void M2Object::collectMeshes(std::vector<HGMesh> &renderedThisFrame, int renderOrder) {
if (!m_loaded) return;
M2SkinProfile* skinData = this->m_skinGeom->getSkinData();
int minBatch = m_api->getConfig()->getM2MinBatch();
int maxBatch = std::min(m_api->getConfig()->getM2MaxBatch(), (const int &) this->m_meshArray.size());
for (int i = minBatch; i < maxBatch; i++) {
float finalTransparency = M2MeshBufferUpdater::calcFinalTransparency(*this, i, skinData);
if ((finalTransparency < 0.0001) ) continue;
this->m_meshArray[i]->setRenderOrder(renderOrder);
renderedThisFrame.push_back(this->m_meshArray[i]);
}
// renderedThisFrame.push_back(occlusionQuery);
}
float M2MeshBufferUpdater::calcFinalTransparency(const M2Object &m2Object, int batchIndex, M2SkinProfile * m2SkinProfile){
auto textMaterial = m2SkinProfile->batches[batchIndex];
int renderFlagIndex = textMaterial->materialIndex;
mathfu::vec4 meshColor = M2Object::getCombinedColor(m2SkinProfile, batchIndex, m2Object.subMeshColors);
float transparency = M2Object::getTransparency(m2SkinProfile, batchIndex, m2Object.transparencies);
float finalTransparency = meshColor.w;
if ( textMaterial->textureCount && !(textMaterial->flags & 0x40)) {
finalTransparency *= transparency;
}
return finalTransparency;
}
enum class MeshType {
eGeneralMesh = 0,
eAdtMesh = 1,
eWmoMesh = 2,
eOccludingQuery = 3,
eM2Mesh = 4,
eParticleMesh = 5,
};
m_isTransparent = m_blendMode > EGxBlendEnum::GxBlend_AlphaKey || !m_depthWrite ;
meshTemplate.blendMode = M2BlendingModeToEGxBlendEnum[material.blending_mode];
@@ -0,0 +1,8 @@
RENDER_ENGINE_DEBUG = False
def render_debug(message: str):
global RENDER_ENGINE_DEBUG
if RENDER_ENGINE_DEBUG:
print('Debug:', message)
@@ -0,0 +1,297 @@
import bpy
import gpu
import mathutils
from typing import Union
from bgl import *
from ...wbs_kernel.render import CWMODrawingBatch
from ...wbs_kernel.render import OpenGLUtils
from .shaders import WMOShaderPermutations, EGxBLend
from .drawing_material import WMODrawingMaterial
from ..drawing_elements import ElementTypes
from ..utils import render_debug
from ..bgl_ext import glCheckError
class WMODrawingBatch:
c_batch: CWMODrawingBatch
# control
mesh_type: int = ElementTypes.WmoMesh
shader: gpu.types.GPUShader
bl_batch_vert_shader_id: int
bl_batch_frag_shader_id: int
# uniform data
draw_material: Union[CWMODrawingBatch, None]
def __init__(self
, c_batch: 'CWMODrawingBatch'
, draw_obj: 'WMODrawingObject'
, context: bpy.types.Context):
self.c_batch = c_batch
self.context = context
self.draw_obj = draw_obj
self.tag_free = False
self.mat_id = self.c_batch.get_mat_id()
try:
self.draw_material = self.draw_obj.draw_mgr.draw_materials.get(
self.draw_obj.bl_obj.data.materials[self.mat_id].name)
except IndexError:
self.draw_material = None
self.create_vao()
self.draw_obj.draw_mgr.draw_elements.add_batch(self)
render_debug('Instantiated drawing batch for object \"{}\"'.format(draw_obj.bl_obj.name))
@property
def is_transparent(self) -> bool:
return False
@property
def priority_plane(self) -> int:
return 0
@property
def layer(self) -> int:
return 0
@property
def is_skybox(self) -> bool:
return False
@property
def bb_center(self) -> mathutils.Vector:
return mathutils.Vector(self.c_batch.bb_center)
@property
def sort_radius(self) -> float:
return self.c_batch.sort_radius
@property
def sort_distance(self):
perspective_mat = self.draw_obj.draw_mgr.region_3d.perspective_matrix
bb_center = self.draw_obj.bl_obj.matrix_world @ self.bb_center
value = (perspective_mat.to_translation() - bb_center).length
if self.draw_material.is_inverted or self.draw_material.is_transformed:
result_point = bb_center * (1.0 / value) if value > 0.00000023841858 else bb_center
sort_dist = perspective_mat.to_translation().length * self.sort_radius
result_point *= sort_dist
value = (bb_center - result_point).length \
if self.draw_material.is_inverted else (bb_center + result_point).length
return value
def create_vao(self):
self.shader = self.determine_valid_shader()
self.c_batch.set_program(self.shader.program)
self.c_batch.create_vao()
glCheckError('Create VAO')
def ensure_context(self):
mat_test = self.draw_material.bl_material
if not mat_test:
self.tag_free = True
return self.tag_free
def _set_active_textures(self):
gl_texture_slots = (
GL_TEXTURE0,
GL_TEXTURE1,
GL_TEXTURE2,
GL_TEXTURE3
)
for i, gl_slot in enumerate(gl_texture_slots):
bind_code = self.draw_material.get_bindcode(i)
if bind_code:
glActiveTexture(gl_slot)
glBindTexture(GL_TEXTURE_2D, bind_code)
def determine_valid_shader(self) -> gpu.types.GPUShader:
shaders = WMOShaderPermutations()
if self.draw_material:
shader_rec = WMOShaderPermutations.get_shader_combo(int(self.draw_material.bl_material.wow_wmo_material.shader))
self.bl_batch_vert_shader_id = shader_rec.vertex_shader
self.bl_batch_frag_shader_id = shader_rec.pixel_shader
return shaders.get_shader_by_id(self.bl_batch_vert_shader_id,
self.bl_batch_frag_shader_id)
else:
return shaders.default_shader
def draw(self):
render_debug('Drawing batch for object \"{}\"'.format(self.draw_obj.bl_obj.name))
bl_obj = self.draw_obj.bl_obj
if not bl_obj.visible_get():
return
if self.tag_free:
return
if self.draw_material:
self.draw_wmo_batch()
else:
self.draw_fallback()
def draw_fallback(self):
glCheckError('drawfallback pre')
self.shader = self.determine_valid_shader()
self.shader.bind()
self.c_batch.set_program(self.shader.program)
self.shader.uniform_float('uViewProjectionMatrix', self.draw_obj.draw_mgr.region_3d.perspective_matrix)
self.shader.uniform_float('uPlacementMatrix', self.draw_obj.bl_obj.matrix_world)
self.shader.uniform_float('uSunDirAndFogStart', self.draw_obj.draw_mgr.sun_dir_and_fog_start)
self.shader.uniform_float('uSunColorAndFogEnd', self.draw_obj.draw_mgr.sun_color_and_fog_end)
self.shader.uniform_float('uAmbientLight', self.draw_obj.draw_mgr.ambient_light)
self.shader.uniform_float('uFogColorAndAlphaTest', (*self.draw_obj.draw_mgr.fog_color, 1.0 / 255.0))
self.shader.uniform_int('UnFogged_IsAffectedByLight_LightCount', (False, True, 0))
glEnable(GL_DEPTH_TEST)
self.c_batch.draw()
glDisable(GL_DEPTH_TEST)
gpu.shader.unbind()
glCheckError('draw fallback post')
def draw_wmo_batch(self):
glCheckError('draw')
#render_debug('Drawing batch for object \"{}\"'.format(self.draw_obj.bl_obj.name))
color_name = self.draw_material.bl_material.wow_m2_material.color
transparency_name = self.draw_material.bl_material.wow_m2_material.transparency
color = self.context.scene.wow_m2_colors[color_name].color if color_name else (1.0, 1.0, 1.0, 1.0)
if transparency_name:
transparency_rec = self.context.scene.wow_m2_transparency.get(transparency_name)
transparency = transparency_rec.value if transparency_rec else 1.0
else:
transparency = 1.0
combined_color = (*color[:3], color[3] * transparency)
u_alpha_test = 128.0 / 255.0 * combined_color[3] \
if self.draw_material.blend_mode.index == EGxBLend.AlphaKey.index else 1.0 / 255.0 # Maybe move this to shader logic?
self._set_active_textures()
self.shader = self.determine_valid_shader()
self.shader.bind()
glCheckError('Pre-link program')
self.c_batch.set_program(self.shader.program)
glCheckError('Post-link program')
# draw
if self.draw_material.depth_culling:
glEnable(GL_DEPTH_TEST)
glDepthMask(GL_TRUE if self.draw_material.depth_write else GL_FALSE)
if self.draw_material.backface_culling:
glEnable(GL_CULL_FACE)
if self.draw_material.blend_mode.blending_enabled:
glEnable(GL_BLEND)
if self.is_skybox:
glDepthRange(0.998, 1.0)
glBlendFunc(self.draw_material.blend_mode.src_color, self.draw_material.blend_mode.dest_color)
# OpenGLUtils.glBlendFuncSeparate(self.draw_material.blend_mode.src_color,
# self.draw_material.blend_mode.dest_color,
# self.draw_material.blend_mode.src_alpha,
# self.draw_material.blend_mode.dest_alpha)
self.shader.uniform_float('uViewProjectionMatrix', self.draw_obj.draw_mgr.region_3d.perspective_matrix)
self.shader.uniform_float('uPlacementMatrix', self.draw_obj.bl_obj.matrix_world)
self.shader.uniform_float('uSunDirAndFogStart', self.draw_obj.draw_mgr.sun_dir_and_fog_start)
self.shader.uniform_float('uSunColorAndFogEnd', self.draw_obj.draw_mgr.sun_color_and_fog_end)
self.shader.uniform_float('uAmbientLight', self.draw_obj.draw_mgr.ambient_light)
self.shader.uniform_float('uFogColorAndAlphaTest', (*self.draw_obj.draw_mgr.fog_color, u_alpha_test))
self.shader.uniform_int('UnFogged_IsAffectedByLight_LightCount', (self.draw_material.is_unfogged,
not self.draw_material.is_unlit, 0))
try:
self.shader.uniform_int('uTexture', 0)
except ValueError:
pass
try:
self.shader.uniform_int('uTexture2', 1)
except ValueError:
pass
try:
self.shader.uniform_int('uTexture3', 2)
except ValueError:
pass
try:
self.shader.uniform_int('uTexture4', 3)
except ValueError:
pass
self.shader.uniform_float('color_Transparency', combined_color)
self.c_batch.draw()
if self.is_skybox:
glDepthRange(0, 0.996)
if self.draw_material.blend_mode.blending_enabled:
glDisable(GL_BLEND)
if self.draw_material.backface_culling:
glDisable(GL_CULL_FACE)
glDepthMask(GL_FALSE if self.draw_material.depth_write else GL_TRUE)
if self.draw_material.depth_culling:
glDisable(GL_DEPTH_TEST)
gpu.shader.unbind()
glCheckError('draw end')
def free(self):
if self.tag_free:
return
self.tag_free = True
self.draw_obj.draw_mgr.draw_elements.remove_batch(self)
@@ -0,0 +1,89 @@
import bpy
from .shaders import EGxBlendRecord, WMOBlendingModeToEGxBlend
class WMODrawingMaterial:
__slots__ = (
'draw_mgr',
'bl_material_name',
'blend_mode',
'backface_culling',
'is_unlit',
'is_unfogged',
'is_exterior_lit',
'night_glow',
'is_window',
'clamp_s',
'clamp_t',
)
blend_mode: EGxBlendRecord
backface_culling: bool
is_unlit: bool
is_unfogged: bool
is_exterior_lit: bool
night_glow: bool
is_window: bool
clamp_s: bool
clamp_t: bool
def __init__(self, material: bpy.types.Material):
self.bl_material_name = material.name
self.update_uniform_data()
@property
def bl_material(self):
try:
return bpy.data.materials[self.bl_material_name]
except KeyError:
return None
def get_texture(self, tex_index: int):
mat = self.bl_material
if mat:
return getattr(mat.wow_wmo_material, 'diff_texture_{}'.format(tex_index + 1))
@property
def texture_count(self):
mat = self.bl_material
counter = 0
if mat:
for i in range(2):
tex = getattr(mat.wow_wmo_material, 'diff_texture_{}'.format(i + 1))
if tex:
counter += 1
return counter
def update_uniform_data(self):
bl_material = self.bl_material
if not bl_material:
return
self.blend_mode = WMOBlendingModeToEGxBlend[int(self.bl_material.wow_wmo_material.blending_mode)]
self.backface_culling = '4' not in bl_material.wow_wmo_material.render_flags
self.is_unlit = '1' in bl_material.wow_wmo_material.render_flags
self.is_unfogged = '2' in bl_material.wow_wmo_material.render_flags
self.is_exterior_lit = '8' in bl_material.wow_wmo_material.render_flags
self.night_glow = '16' in bl_material.wow_wmo_material.render_flags
self.is_window = '32' in bl_material.wow_wmo_material.render_flags
self.clamp_s = '64' in bl_material.wow_wmo_material.render_flags
self.clamp_t = '128' in bl_material.wow_wmo_material.render_flags
def get_bindcode(self, tex_index: int) -> int:
texture = self.get_texture(tex_index)
if texture:
if not texture.bindcode:
texture.gl_load()
return texture.bindcode
return 0
@@ -0,0 +1,108 @@
import traceback
import bpy
import numpy as np
from mathutils import Matrix
from typing import List
from .drawing_batch import M2DrawingBatch
from ..utils import render_debug
from ...wbs_kernel.render import CM2DrawingMesh, CM2DrawingBatch
from ..bgl_ext import glCheckError
class M2DrawingObject:
batches: List[CM2DrawingBatch]
def __init__(self
, bl_obj: bpy.types.Object
, drawing_mgr: 'M2DrawingManager'
, context: bpy.types.Context
, is_skybox: bool = False):
self.context = context
self.draw_mgr = drawing_mgr
self.bl_obj_name = bl_obj.name
self.is_skybox = is_skybox
self.is_dirty = True
self.is_batching_valid = False
self.mesh_ptr = bl_obj.data.as_pointer()
self.c_mesh = CM2DrawingMesh(self.mesh_ptr)
self.batches = []
bl_obj.data.calc_loop_triangles()
render_debug('Initialized drawing object \"{}\"'.format(self.bl_obj_name))
self.update_geometry()
def update_geometry(self, bl_obj: bpy.types.Object = None):
if bl_obj:
self.c_mesh.update_mesh_pointer(bl_obj.data.as_pointer())
bl_obj.data.calc_loop_triangles()
self.is_batching_valid = self.c_mesh.update_geometry(not(self.context.screen.is_animation_playing or self.bl_obj.mode != 'OBJECT'))
self.is_dirty = True
def update_geometry_opengl(self, bl_obj: bpy.types.Object = None):
self.c_mesh.update_buffers()
if not self.is_batching_valid:
for batch in self.batches:
batch.free()
self.batches = \
[M2DrawingBatch(c_batch, self, self.context) for c_batch in self.c_mesh.get_drawing_batches()]
self.is_dirty = False
@property
def bl_obj(self):
try:
return bpy.data.objects[self.bl_obj_name]
except KeyError:
self.free()
def free(self):
for batch in self.batches:
batch.free()
del self.draw_mgr.m2_objects[self.bl_obj_name]
render_debug('Freed drawing object \"{}\"'.format(self.bl_obj_name))
'''
def update_bone_matrices(self):
rig = self.bl_rig
for i, pbone in enumerate(rig.pose.bones):
self.bone_matrices[i] = [j[i] for i in range(4) for j in pbone.matrix_channel]
def create_batches_from_armature(self, rig: bpy.types.Object):
for obj in filter(lambda x: x.type == 'MESH', rig.children):
# Limit bone influences to 4. TODO: rework to be non-destructive!
"""
if obj.vertex_groups:
active_obj = bpy.context.view_layer.objects.active
bpy.context.view_layer.objects.active = obj
bpy.ops.object.vertex_group_limit_total()
bpy.context.view_layer.objects.active = active_obj
"""
self.create_batch_from_object(obj)
def create_batch_from_object(self, obj: bpy.types.Object):
self.batches[obj.name] = M2DrawingBatch(obj, self, self.context)
'''
@@ -0,0 +1,173 @@
import os
import gpu
from enum import IntEnum
from ctypes import c_uint, c_uint8
from collections import namedtuple
from typing import Dict, Tuple
from ...utils.misc import singleton, Sequence
from ..shaders import ShaderPermutationsManager
from bgl import *
class WMOPixelShader(IntEnum):
NoShader = -1,
MapObjDiffuse = 0,
MapObjSpecular = 1,
MapObjMetal = 2,
MapObjEnv = 3,
MapObjOpaque = 4,
MapObjEnvMetal = 5,
MapObjTwoLayerDiffuse = 6, # MapObjComposite
MapObjTwoLayerEnvMetal = 7,
MapObjTwoLayerTerrain = 8,
MapObjDiffuseEmissive = 9,
MapObjMaskedEnvMetal = 10,
MapObjEnvMetalEmissive = 11,
MapObjTwoLayerDiffuseOpaque = 12,
MapObjTwoLayerDiffuseEmissive = 13,
MapObjAdditiveMaskedEnvMetal = 14,
MapObjTwoLayerDiffuseMod2x = 15,
MapObjTwoLayerDiffuseMod2xNA = 16,
MapObjTwoLayerDiffuseAlpha = 17,
MapObjLod = 18,
MapObjParallax = 19
class WMOVertexShader(IntEnum):
NoShader = -1,
MapObjDiffuse_T1 = 0,
MapObjDiffuse_T1_Refl = 1,
MapObjDiffuse_T1_Env_T2 = 2,
MapObjSpecular_T1 = 3,
MapObjDiffuse_Comp = 4,
MapObjDiffuse_Comp_Refl = 5,
MapObjDiffuse_Comp_Terrain = 6,
MapObjDiffuse_CompAlpha = 7,
MapObjParallax = 8,
EGxBlendRecord = namedtuple('EGxBlendRecord',
['blending_enabled', 'src_color', 'dest_color', 'src_alpha', 'dest_alpha', 'index'])
class EGxBLend(metaclass=Sequence):
Opaque = EGxBlendRecord(False, GL_ONE, GL_ZERO, GL_ONE, GL_ZERO, 0)
AlphaKey = EGxBlendRecord(False, GL_ONE, GL_ZERO, GL_ONE, GL_ZERO, 1)
Alpha = EGxBlendRecord(True, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, 2)
Add = EGxBlendRecord(True, GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE, 3)
Mod = EGxBlendRecord(True, GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO, 4)
Mod2x = EGxBlendRecord(True, GL_DST_COLOR, GL_SRC_COLOR, GL_DST_ALPHA, GL_SRC_ALPHA, 5)
ModAdd = EGxBlendRecord(True, GL_DST_COLOR, GL_ONE, GL_DST_ALPHA, GL_ONE, 6)
InvSrcAlphaAdd = EGxBlendRecord(True, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, 7)
InvSrcAlphaOpaque = EGxBlendRecord(True, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, 8)
SrcAlphaOpaque = EGxBlendRecord(True, GL_SRC_ALPHA, GL_ZERO, GL_SRC_ALPHA, GL_ZERO, 9)
NoAlphaAdd = EGxBlendRecord(True, GL_ONE, GL_ONE, GL_ZERO, GL_ONE, 10)
ConstantAlpha = EGxBlendRecord(True, GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA, GL_CONSTANT_ALPHA,
GL_ONE_MINUS_CONSTANT_ALPHA, 11)
Screen = EGxBlendRecord(True, GL_ONE_MINUS_DST_COLOR, GL_ONE, GL_ONE, GL_ZERO, 12)
BlendAdd = EGxBlendRecord(True, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, 13)
class WMOBlendingModeToEGxBlend(metaclass=Sequence):
Blend_Opaque = EGxBLend.Opaque
Blend_AlphaKey = EGxBLend.AlphaKey
Blend_Alpha = EGxBLend.Alpha
Blend_NoAlphaAdd = EGxBLend.NoAlphaAdd
Blend_Add = EGxBLend.Add
Blend_Mod = EGxBLend.Mod
Blend_Mod2x = EGxBLend.Mod2x
Blend_BlendAdd = EGxBLend.BlendAdd
WMOShaderTableRecord = namedtuple('WMOShaderTableRecord', ['pixel_shader', 'vertex_shader'])
class WMOShaderTable(metaclass=Sequence):
MapObjDiffuse = WMOShaderTableRecord(WMOPixelShader.MapObjDiffuse, WMOVertexShader.MapObjDiffuse_T1)
MapObjSpecular = WMOShaderTableRecord(WMOPixelShader.MapObjSpecular, WMOVertexShader.MapObjSpecular_T1)
MapObjMetal = WMOShaderTableRecord(WMOPixelShader.MapObjMetal, WMOVertexShader.MapObjSpecular_T1)
MapObjEnv = WMOShaderTableRecord(WMOPixelShader.MapObjEnv, WMOVertexShader.MapObjDiffuse_T1_Refl)
MapObjOpaque = WMOShaderTableRecord(WMOPixelShader.MapObjOpaque, WMOVertexShader.MapObjDiffuse_T1)
MapObjEnvMetal = WMOShaderTableRecord(WMOPixelShader.MapObjEnvMetal, WMOVertexShader.MapObjDiffuse_T1_Refl)
MapObjTwoLayerDiffuse = WMOShaderTableRecord(WMOPixelShader.MapObjTwoLayerDiffuse,
WMOVertexShader.MapObjDiffuse_Comp)
MapObjTwoLayerEnvMetal = WMOShaderTableRecord(WMOPixelShader.MapObjTwoLayerEnvMetal,
WMOVertexShader.MapObjDiffuse_T1)
TwoLayerTerrain = WMOShaderTableRecord(WMOPixelShader.MapObjTwoLayerTerrain,
WMOVertexShader.MapObjDiffuse_Comp_Terrain)
MapObjDiffuseEmissive = WMOShaderTableRecord(WMOPixelShader.MapObjDiffuseEmissive,
WMOVertexShader.MapObjDiffuse_Comp)
waterWindow = WMOShaderTableRecord(WMOPixelShader.NoShader,
WMOVertexShader.NoShader)
MapObjMaskedEnvMetal = WMOShaderTableRecord(WMOPixelShader.MapObjMaskedEnvMetal,
WMOVertexShader.MapObjDiffuse_T1_Env_T2)
MapObjEnvMetalEmissive = WMOShaderTableRecord(WMOPixelShader.MapObjEnvMetalEmissive,
WMOVertexShader.MapObjDiffuse_T1_Env_T2)
TwoLayerDiffuseOpaque = WMOShaderTableRecord(WMOPixelShader.MapObjTwoLayerDiffuseOpaque,
WMOVertexShader.MapObjDiffuse_Comp)
submarineWindow = WMOShaderTableRecord(WMOPixelShader.NoShader, WMOVertexShader.NoShader)
TwoLayerDiffuseEmissive = WMOShaderTableRecord(WMOPixelShader.MapObjTwoLayerDiffuseEmissive,
WMOVertexShader.MapObjDiffuse_Comp)
MapObjDiffuseTerrain = WMOShaderTableRecord(WMOPixelShader.MapObjDiffuse,
WMOVertexShader.MapObjDiffuse_T1)
MapObjAdditiveMaskedEnvMetal = WMOShaderTableRecord(WMOPixelShader.MapObjAdditiveMaskedEnvMetal,
WMOVertexShader.MapObjDiffuse_T1_Env_T2)
MapObjTwoLayerDiffuseMod2x = WMOShaderTableRecord(WMOPixelShader.MapObjTwoLayerDiffuseMod2x,
WMOVertexShader.MapObjDiffuse_CompAlpha)
MapObjTwoLayerDiffuseMod2xNA = WMOShaderTableRecord(WMOPixelShader.MapObjTwoLayerDiffuseMod2xNA,
WMOVertexShader.MapObjDiffuse_Comp)
MapObjTwoLayerDiffuseAlpha = WMOShaderTableRecord(WMOPixelShader.MapObjTwoLayerDiffuseAlpha,
WMOVertexShader.MapObjDiffuse_CompAlpha)
MapObjLod = WMOShaderTableRecord(WMOPixelShader.MapObjLod,
WMOVertexShader.MapObjDiffuse_T1)
MapObjParallax = WMOShaderTableRecord(WMOPixelShader.MapObjParallax,
WMOVertexShader.MapObjParallax)
@singleton
class WMOShaderPermutations(ShaderPermutationsManager):
shader_source_path = 'wmo_shader'
@staticmethod
def get_shader_combo_index(vertex_shader_id: int, pixel_shader_id: int):
for record in WMOShaderTable:
if record.value.vertex_shader == vertex_shader_id and record.value.pixel_shader == pixel_shader_id:
return record.index
def get_shader_combo(self, id: int):
# TODO: ugly
count = 0
for i, record in enumerate(WMOShaderTable):
if i == count:
return record
count += 1