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 Apr 29, 2021
1 parent 91bace8 commit 78d1c1f
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 0 deletions.
44 changes: 44 additions & 0 deletions korlib/bumpmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,50 @@ 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;
int additive = 0;
if (!PyArg_ParseTuple(args, "O|i", &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) {
if (x < y)
x = y;

*pix++ = MakeUInt32Color(1.0f, 1.0f, 1.0f, x);
} 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):
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

tr0 = layer_props.funky_near_trans
op0 = layer_props.funky_near_opaq
tr1 = layer_props.funky_far_trans
op1 = layer_props.funky_far_opaq

if funky_type != "FunkyDist":
tr0 = max(min(tr0, 180.0), 0.0)
op0 = max(min(op0, 180.0), 0.0)
tr1 = max(min(tr1, 180.0), 0.0)
op1 = max(min(op1, 180.0), 0.0)

if tr0 > tr1:
tr0, tr1 = tr1, tr0
op0, op1 = op1, op0

if tr0 == op0 or op1 == tr1:
return None

additive = tr0 > op0 and op1 > tr1

if funky_type != "FunkyDist":
tr0 = math.cos(tr0 * (math.pi / 180.0))
op0 = math.cos(op0 * (math.pi / 180.0))
op1 = math.cos(op1 * (math.pi / 180.0))
tr1 = math.cos(tr1 * (math.pi / 180.0))

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

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

if op1 != tr1:
uvwXfm[1,2] = -1.0 / (tr1 - op1)
uvwXfm[1,3] = uvwXfm[1,2] * -tr1
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
24 changes: 24 additions & 0 deletions korman/korlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,30 @@
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*j*4
end = start + 4

if additive:
if x < y:
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")
22 changes: 22 additions & 0 deletions korman/ui/ui_texture.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,25 @@ 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 78d1c1f

Please sign in to comment.