Skip to content

Commit

Permalink
Add Funky Blending layer support
Browse files Browse the repository at this point in the history
  • Loading branch information
dpogue committed May 2, 2021
1 parent 91bace8 commit 553481f
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 0 deletions.
41 changes: 41 additions & 0 deletions korlib/bumpmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,47 @@ static uint32_t MakeUInt32Color(float r, float g, float b, float a) {
(uint32_t(b * 255.9f) << 0);
}

PyObject* create_funky_ramp(PyObject*, PyObject* args) {
static const int kLUTHeight = 16;
static const int kLUTWidth = 16;
static const int kBufSz = kLUTWidth * kLUTHeight * sizeof(uint32_t);

pyMipmap* pymipmap;
bool additive = false;
if (!PyArg_ParseTuple(args, "O|b", &pymipmap, &additive)) {
PyErr_SetString(PyExc_TypeError, "create_funky_ramp expects a plMipmap and an optional boolean");
return NULL;
}

plMipmap* texture = plMipmap::Convert(pymipmap->fThis, false);
if (!texture) {
PyErr_SetString(PyExc_TypeError, "create_funky_ramp expects a plMipmap");
return NULL;
}

texture->Create(kLUTWidth, kLUTHeight, 1, plBitmap::kUncompressed, plBitmap::kRGB8888);

uint8_t data[kBufSz];
uint32_t* pix = (uint32_t*)data;

for (int i = 0; i < kLUTHeight; ++i) {
for (int j = 0; j < kLUTWidth; ++j) {
float x = float(j) / (kLUTWidth - 1);
float y = float(i) / (kLUTHeight - 1);

if (additive) {
*pix++ = MakeUInt32Color(1.0f, 1.0f, 1.0f, std::max(x, y));
} else {
*pix++ = MakeUInt32Color(1.0f, 1.0f, 1.0f, x * y);
}
}
}

texture->setImageData(data, kBufSz);

Py_RETURN_NONE;
}

PyObject* create_bump_LUT(PyObject*, PyObject* args) {
static const int kLUTHeight = 16;
static const int kLUTWidth = 16;
Expand Down
1 change: 1 addition & 0 deletions korlib/bumpmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "korlib.h"

PyObject* create_funky_ramp(PyObject*, PyObject* args);
PyObject* create_bump_LUT(PyObject*, PyObject* args);

#endif // _KORLIB_BUMPMAP_H
1 change: 1 addition & 0 deletions korlib/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#define KORLIB_API_VERSION 2

static PyMethodDef korlib_Methods[] = {
{ _pycs("create_funky_ramp"), (PyCFunction)create_funky_ramp, METH_VARARGS, NULL },
{ _pycs("create_bump_LUT"), (PyCFunction)create_bump_LUT, METH_VARARGS, NULL },
{ _pycs("inspect_vorbisfile"), (PyCFunction)inspect_vorbisfile, METH_VARARGS, NULL },
{ _pycs("scale_image"), (PyCFunction)scale_image, METH_KEYWORDS | METH_VARARGS, NULL },
Expand Down
92 changes: 92 additions & 0 deletions korman/exporter/material.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,11 @@ def export_material(self, bo, bm):
if i+1 < curr_stencils:
stencil_layer.state.miscFlags |= hsGMatState.kMiscBindNext
hsgmat.addLayer(stencil_layer.key)
if slot.texture.plasma_layer.funky_type != "FunkyNone":
funky_ramp = self._export_funky_slot(bo, bm, hsgmat, slot, idx)
if funky_ramp:
tex_layer.state.miscFlags |= hsGMatState.kMiscBindNext
hsgmat.addLayer(funky_ramp.key)

# Plasma makes several assumptions that every hsGMaterial has at least one layer. If this
# material had no Textures, we will need to initialize a default layer
Expand Down Expand Up @@ -357,6 +362,93 @@ def export_waveset_material(self, bo, bm):
# Wasn't that easy?
return hsgmat.key

def _export_funky_slot(self, bo, bm, hsgmat, slot, idx) -> plLayerInterface:
name = "{}_{}_funkRamp".format(hsgmat.key.name, slot.name)
self._report.msg("Exporting Plasma Funky Ramp Layer '{}'", name, indent=2)

texture = slot.texture
layer_props = texture.plasma_layer
funky_type = layer_props.funky_type

near_trans = layer_props.funky_near_trans
near_opaq = layer_props.funky_near_opaq
far_trans = layer_props.funky_far_trans
far_opaq = layer_props.funky_far_opaq

if funky_type != "FunkyDist":
near_trans = max(min(near_trans, 180.0), 0.0)
near_opaq = max(min(near_opaq, 180.0), 0.0)
far_trans = max(min(far_trans, 180.0), 0.0)
far_opaq = max(min(far_opaq, 180.0), 0.0)

if near_trans > far_trans:
near_trans, far_trans = far_trans, near_trans
near_opaq, far_opaq = far_opaq, near_opaq

if near_trans == near_opaq or far_opaq == far_trans:
return None

additive = near_trans > near_opaq and far_opaq > far_trans

if funky_type != "FunkyDist":
near_trans = math.cos(near_trans * (math.pi / 180.0))
near_opaq = math.cos(near_opaq * (math.pi / 180.0))
far_opaq = math.cos(far_opaq * (math.pi / 180.0))
far_trans = math.cos(far_trans * (math.pi / 180.0))

uvwXfm = hsMatrix44()
uvwXfm[0,0] = uvwXfm[1,1] = uvwXfm[2,2] = 0.0

if near_opaq != near_trans:
uvwXfm[0,2] = -1.0 / (near_trans - near_opaq)
uvwXfm[0,3] = uvwXfm[0,2] * -near_trans
else:
uvwXfm[0,3] = 1.0

if far_opaq != far_trans:
uvwXfm[1,2] = -1.0 / (far_trans - far_opaq)
uvwXfm[1,3] = uvwXfm[1,2] * -far_trans
else:
uvwXfm[1,3] = 1.0

ramp_layer = self._mgr.find_create_object(plLayer, name=name, bl=bo)

rampName = "FunkyRampAdd" if additive else "FunkyRampMult"
page = self._mgr.get_textures_page(ramp_layer.key)
ramp_key = self._mgr.find_key(plMipmap, loc=page, name=rampName)

if ramp_key is None:
funkRamp = plMipmap(rampName, 16, 16, 1, plBitmap.kUncompressed, plBitmap.kRGB8888)
create_funky_ramp(funkRamp, additive)
self._mgr.AddObject(page, funkRamp)
ramp_key = funkRamp.key

ramp_layer.texture = ramp_key
ramp_layer.ambient = hsColorRGBA(1.0, 1.0, 1.0, 1.0)
ramp_layer.preshade = hsColorRGBA(0.0, 0.0, 0.0, 1.0)
ramp_layer.runtime = hsColorRGBA(0.0, 0.0, 0.0, 1.0)
ramp_layer.specular = hsColorRGBA(0.0, 0.0, 0.0, 1.0)

ramp_layer.state.ZFlags = hsGMatState.kZNoZWrite
ramp_layer.state.clampFlags = hsGMatState.kClampTexture
ramp_layer.state.blendFlags = hsGMatState.kBlendAlpha | hsGMatState.kBlendNoTexColor | hsGMatState.kBlendAlphaMult

ramp_layer.transform = uvwXfm

if funky_type == "FunkyDist":
ramp_layer.UVWSrc = plLayerInterface.kUVWPosition
ramp_layer.state.miscFlags |= hsGMatState.kMiscNoShadowAlpha
elif funky_type == "FunkyNormal":
ramp_layer.UVWSrc = plLayerInterface.kUVWNormal
elif funky_type == "FunkyUp":
ramp_layer.UVWSrc = plLayerInterface.kUVWNormal
ramp_layer.state.miscFlags |= hsGMatState.kMiscOrthoProjection
elif funky_type == "FunkyReflect":
ramp_layer.UVWSrc = plLayerInterface.kUVWReflect

return ramp_layer


def export_bumpmap_slot(self, bo, bm, hsgmat, slot, idx):
name = "{}_{}".format(hsgmat.key.name, slot.name)
self._report.msg("Exporting Plasma Bumpmap Layers for '{}'", name, indent=2)
Expand Down
22 changes: 22 additions & 0 deletions korman/korlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,28 @@
msg = "Korlib C Module did not load correctly."
print(msg, "Using PyKorlib :(", sep=' ')

def create_funky_ramp(mipmap, additive=False):
kLUTHeight = 16
kLUTWidth = 16

buf = bytearray(kLUTHeight * kLUTWidth * 4)

for i in range(kLUTHeight):
for j in range(kLUTWidth):
x = j / (kLUTWidth - 1);
y = i / (kLUTHeight - 1);

start = i * kLUTWidth * 4 + j * 4
end = start + 4

if additive:
x = max(x, y)
buf[start:end] = [b for b in (255, 255, 255, int(x * 255.9))]
else:
buf[start:end] = [b for b in (255, 255, 255, int((x * y) * 255.9))]

mipmap.setRawImage(bytes(buf))

def create_bump_LUT(mipmap):
kLUTHeight = 16
kLUTWidth = 16
Expand Down
21 changes: 21 additions & 0 deletions korman/properties/prop_texture.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,24 @@ class PlasmaLayer(bpy.types.PropertyGroup):
description="Don't save the depth information, allowing rendering of layers behind this one",
default=False,
options=set())

funky_type = EnumProperty(name="Funky Blending Type",
description="Type of special funky layer blending",
items=[("FunkyNone", "None", "No funky layer blending"),
("FunkyDist", "Distance", "Distance-based funky layer blending"),
("FunkyNormal", "Normal", "Normal angle-based funky layer blending"),
("FunkyReflect", "Reflect", "Reflection angle-based funky layer blending"),
("FunkyUp", "Up", "Upwards angle-based funky layer blending")],
default="FunkyNone")
funky_near_trans = FloatProperty(name="Near Transparent",
description="Nearest distance at which the layer is fully transparent",
min=0.0, default=0.0, subtype="DISTANCE", unit="LENGTH")
funky_near_opaq = FloatProperty(name="Near Opaque",
description="Nearest distance at which the layer is fully opaque",
min=0.0, default=0.0, subtype="DISTANCE", unit="LENGTH")
funky_far_opaq = FloatProperty(name="Far Opaque",
description="Farthest distance at which the layer is fully opaque",
min=0.0, default=15.0, subtype="DISTANCE", unit="LENGTH")
funky_far_trans = FloatProperty(name="Far Transparent",
description="Farthest distance at which the layer is fully transparent",
min=0.0, default=20.0, subtype="DISTANCE", unit="LENGTH")
23 changes: 23 additions & 0 deletions korman/ui/ui_texture.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,26 @@ def _has_animation_data(self, context):
return True

return False


class PlasmaFunkyLayerPanel(TextureButtonsPanel, bpy.types.Panel):
bl_label = "Plasma Funky Layer"

def draw(self, context):
texture, slot = context.texture, getattr(context, "texture_slot", None)
use_stencil = slot.use_stencil if slot is not None else False
layer_props = texture.plasma_layer
layout = self.layout

layout.prop(layer_props, "funky_type")

if layer_props.funky_type != "FunkyNone":
col = layout.column(align=True)
col.prop(layer_props, "funky_near_trans")
col.prop(layer_props, "funky_near_opaq")
col.prop(layer_props, "funky_far_opaq")
col.prop(layer_props, "funky_far_trans")

if layer_props.funky_type != "FunkyDist":
# Mention that values are angles
layout.label("Values should be viewing angles in degrees between 0 and 180.", icon="RESTRICT_VIEW_OFF")

0 comments on commit 553481f

Please sign in to comment.