Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/main/java/rs117/hd/opengl/uniforms/UBOLights.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ public String getUniformBlockName() {
return lights != null ? "UBOLights" : "UBOLightsCulling";
}

public void setLight(int lightIdx, float[] position, float[] color) {
public void setLight(int lightIdx, float[] position, float[] color, float[] direction) {
if (lightIdx >= 0 && lightIdx < MAX_LIGHTS) {
if (lights != null) {
var struct = lights[lightIdx];
struct.position.set(position);
struct.color.set(color);
struct.direction.set(direction);
} else {
lightPositions[lightIdx].set(position);
}
Expand All @@ -36,5 +37,6 @@ public void setLight(int lightIdx, float[] position, float[] color) {
public static class LightStruct extends UniformBuffer.StructProperty {
public Property position = addProperty(PropertyType.FVec4, "position");
public Property color = addProperty(PropertyType.FVec4, "color");
public Property direction = addProperty(PropertyType.FVec4, "direction");
}
}
20 changes: 17 additions & 3 deletions src/main/java/rs117/hd/renderer/legacy/LegacyRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,7 @@ public void drawScene(double cameraX, double cameraY, double cameraZ, double cam
frameTimer.begin(Timer.UPDATE_LIGHTS);
final float[] lightPosition = new float[4];
final float[] lightColor = new float[4];
final float[] lightDirection = new float[4];
for (int i = 0; i < sceneContext.numVisibleLights; i++) {
final Light light = sceneContext.lights.get(i);
final float lightRadiusSq = light.radius * light.radius;
Expand All @@ -724,16 +725,29 @@ public void drawScene(double cameraX, double cameraY, double cameraZ, double cam
lightColor[0] = light.color[0] * light.strength;
lightColor[1] = light.color[1] * light.strength;
lightColor[2] = light.color[2] * light.strength;
lightColor[3] = 0.0f;

plugin.uboLights.setLight(i, lightPosition, lightColor);
if (light.def.outerConeAngle > 0) {
lightColor[3] = (float) Math.cos(Math.toRadians(light.def.outerConeAngle));
lightDirection[0] = light.direction[0];
lightDirection[1] = light.direction[1];
lightDirection[2] = light.direction[2];
lightDirection[3] = (float) Math.cos(Math.toRadians(light.def.innerConeAngle));
} else {
lightColor[3] = 0.0f;
lightDirection[0] = 0;
lightDirection[1] = 0;
lightDirection[2] = 0;
lightDirection[3] = 0;
}

plugin.uboLights.setLight(i, lightPosition, lightColor, lightDirection);

if (plugin.configTiledLighting) {
// Pre-calculate the view space position of the light, to save having to do the multiplication in the culling shader
lightPosition[3] = 1.0f;
Mat4.mulVec(lightPosition, plugin.viewMatrix, lightPosition);
lightPosition[3] = lightRadiusSq; // Restore lightRadiusSq
plugin.uboLightsCulling.setLight(i, lightPosition, lightColor);
plugin.uboLightsCulling.setLight(i, lightPosition, lightColor, lightDirection);
}
}

Expand Down
20 changes: 17 additions & 3 deletions src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,7 @@ private void preSceneDrawTopLevel(
frameTimer.begin(Timer.UPDATE_LIGHTS);
final float[] lightPosition = new float[4];
final float[] lightColor = new float[4];
final float[] lightDirection = new float[4];
for (int i = 0; i < ctx.sceneContext.numVisibleLights; i++) {
final Light light = ctx.sceneContext.lights.get(i);
final float lightRadiusSq = light.radius * light.radius;
Expand All @@ -471,16 +472,29 @@ private void preSceneDrawTopLevel(
lightColor[0] = light.color[0] * light.strength;
lightColor[1] = light.color[1] * light.strength;
lightColor[2] = light.color[2] * light.strength;
lightColor[3] = 0.0f;

plugin.uboLights.setLight(i, lightPosition, lightColor);
if (light.def.outerConeAngle > 0) {
lightColor[3] = (float) Math.cos(Math.toRadians(light.def.outerConeAngle));
lightDirection[0] = light.direction[0];
lightDirection[1] = light.direction[1];
lightDirection[2] = light.direction[2];
lightDirection[3] = (float) Math.cos(Math.toRadians(light.def.innerConeAngle));
} else {
lightColor[3] = 0.0f;
lightDirection[0] = 0;
lightDirection[1] = 0;
lightDirection[2] = 0;
lightDirection[3] = 0;
}

plugin.uboLights.setLight(i, lightPosition, lightColor, lightDirection);

if (plugin.configTiledLighting) {
// Pre-calculate the view space position of the light, to save having to do the multiplication in the culling shader
lightPosition[3] = 1.0f;
Mat4.mulVec(lightPosition, plugin.viewMatrix, lightPosition);
lightPosition[3] = lightRadiusSq; // Restore lightRadiusSq
plugin.uboLightsCulling.setLight(i, lightPosition, lightColor);
plugin.uboLightsCulling.setLight(i, lightPosition, lightColor, lightDirection);
}
}

Expand Down
21 changes: 20 additions & 1 deletion src/main/java/rs117/hd/scene/GamevalManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@
public class GamevalManager {
private static final ResourcePath GAMEVAL_PATH = Props
.getFile("rlhd.gameval-path", () -> path(GamevalManager.class, "gamevals.json"));

private static final String NPC_KEY = "npcs";
private static final String OBJECT_KEY = "objects";
private static final String ANIM_KEY = "anims";
private static final String SPOTANIM_KEY = "spotanims";
private static final String ITEM_KEY = "items";

@Inject
private HdPlugin plugin;
Expand All @@ -50,6 +50,7 @@ private static void clearGamevals() {
GAMEVALS.put(OBJECT_KEY, Collections.emptyMap());
GAMEVALS.put(ANIM_KEY, Collections.emptyMap());
GAMEVALS.put(SPOTANIM_KEY, Collections.emptyMap());
GAMEVALS.put(ITEM_KEY, Collections.emptyMap());
}

public void startUp() throws IOException {
Expand Down Expand Up @@ -99,6 +100,10 @@ public Map<String, Integer> getSpotanims() {
return GAMEVALS.get(SPOTANIM_KEY);
}

public Map<String, Integer> getItems() {
return GAMEVALS.get(ITEM_KEY);
}

public int getNpcId(String name) {
return getNpcs().get(name);
}
Expand All @@ -115,6 +120,10 @@ public int getSpotanimId(String name) {
return getSpotanims().get(name);
}

public int getItemId(String name) {
return getItems().get(name);
}

public String getNpcName(int id) {
return getName(NPC_KEY, id);
}
Expand All @@ -131,6 +140,10 @@ public String getSpotanimName(int id) {
return getName(SPOTANIM_KEY, id);
}

public String getItemName(int id) {
return getName(ITEM_KEY, id);
}

@Slf4j
@RequiredArgsConstructor
private abstract static class GamevalAdapter extends TypeAdapter<HashSet<Integer>> {
Expand Down Expand Up @@ -230,4 +243,10 @@ public SpotanimAdapter() {
super(SPOTANIM_KEY);
}
}

public static class ItemAdapter extends GamevalAdapter {
public ItemAdapter() {
super(ITEM_KEY);
}
}
}
77 changes: 76 additions & 1 deletion src/main/java/rs117/hd/scene/LightManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.*;
import net.runelite.api.coords.*;
import net.runelite.api.kit.KitType;
import net.runelite.api.events.*;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
Expand Down Expand Up @@ -103,6 +104,7 @@ public class LightManager {
private final ListMultimap<Integer, LightDefinition> OBJECT_LIGHTS = ArrayListMultimap.create();
private final ListMultimap<Integer, LightDefinition> PROJECTILE_LIGHTS = ArrayListMultimap.create();
private final ListMultimap<Integer, LightDefinition> GRAPHICS_OBJECT_LIGHTS = ArrayListMultimap.create();
private final ListMultimap<Integer, LightDefinition> EQUIPMENT_LIGHTS = ArrayListMultimap.create();

private final Renderable[] imposterRenderables = new Renderable[2];
private boolean reloadLights;
Expand All @@ -128,6 +130,7 @@ public void loadConfig(Gson gson, ResourcePath path) {
OBJECT_LIGHTS.clear();
PROJECTILE_LIGHTS.clear();
GRAPHICS_OBJECT_LIGHTS.clear();
EQUIPMENT_LIGHTS.clear();

for (LightDefinition lightDef : lights) {
lightDef.normalize();
Expand All @@ -141,6 +144,7 @@ public void loadConfig(Gson gson, ResourcePath path) {
lightDef.objectIds.forEach(id -> OBJECT_LIGHTS.put(id, lightDef));
lightDef.projectileIds.forEach(id -> PROJECTILE_LIGHTS.put(id, lightDef));
lightDef.graphicsObjectIds.forEach(id -> GRAPHICS_OBJECT_LIGHTS.put(id, lightDef));
lightDef.equipmentIds.forEach(id -> EQUIPMENT_LIGHTS.put(id, lightDef));
}

log.debug("Loaded {} lights", lights.length);
Expand Down Expand Up @@ -179,6 +183,11 @@ public void update(@Nonnull SceneContext sceneContext, int[] cameraShift, float[
addNpcLights(npc);
addSpotanimLights(npc);
});

for (Player player : client.getTopLevelWorldView().players()) {
if (player != null)
addEquipmentLights(player);
}
}

// These should never occur, but just in case...
Expand Down Expand Up @@ -348,7 +357,20 @@ public void update(@Nonnull SceneContext sceneContext, int[] cameraShift, float[
lerpX
);
float tileHeight = mix(heightSouth, heightNorth, lerpY);
light.origin[1] = (int) tileHeight - 1 - light.def.height;
if (light.equipmentItemId != -1 && light.def.heightFromModel >= 0) {
try {
Model model = light.actor.getModel();
if (model != null) {
light.origin[1] = (int) tileHeight - 1 - (int) (model.getModelHeight() * light.def.heightFromModel);
} else {
light.origin[1] = (int) tileHeight - 1 - light.def.height;
}
} catch (Exception ex) {
light.origin[1] = (int) tileHeight - 1 - light.def.height;
}
} else {
light.origin[1] = (int) tileHeight - 1 - light.def.height;
}
}
}
}
Expand Down Expand Up @@ -389,6 +411,18 @@ public void update(@Nonnull SceneContext sceneContext, int[] cameraShift, float[
light.pos[2] += offsetY;
}

if (light.def.outerConeAngle > 0) {
float yawRad = light.orientation * JAU_TO_RAD;
float pitchRad = light.def.conePitch * DEG_TO_RAD;
float yawSin = sin(yawRad);
float yawCos = cos(yawRad);
float pitchCos = cos(pitchRad);
float pitchSin = sin(pitchRad);
light.direction[0] = -yawSin * pitchCos;
light.direction[1] = -pitchSin;
light.direction[2] = -yawCos * pitchCos;
}

// This is a little bit slow, so only update it when necessary
if (light.prevPlane != light.plane) {
light.prevPlane = light.plane;
Expand Down Expand Up @@ -770,6 +804,43 @@ private void addNpcLights(NPC npc)
}
}

private void addEquipmentLights(Player player) {
var sceneContext = plugin.getSceneContext();
if (sceneContext == null)
return;

PlayerComposition comp = player.getPlayerComposition();
if (comp == null)
return;

for (KitType slot : KitType.values()) {
int itemId = comp.getEquipmentId(slot);
if (itemId == -1)
continue;

for (LightDefinition def : EQUIPMENT_LIGHTS.get(itemId)) {
boolean isDuplicate = sceneContext.lights.stream()
.anyMatch(light ->
light.actor == player &&
light.equipmentItemId == itemId &&
light.def == def &&
!light.markedForRemoval);
if (isDuplicate)
continue;

Light light = new Light(def);
light.plane = -1;
light.actor = player;
light.equipmentItemId = itemId;
sceneContext.lights.add(light);
}
}
}

private void removeEquipmentLights(Player player) {
removeLightIf(light -> light.actor == player && light.equipmentItemId != -1);
}

private void handleObjectSpawn(TileObject object) {
var sceneContext = plugin.getSceneContext();
if (sceneContext != null)
Expand Down Expand Up @@ -1045,11 +1116,15 @@ public void onNpcDespawned(NpcDespawned despawn) {
@Subscribe
public void onPlayerSpawned(PlayerSpawned spawn) {
addSpotanimLights(spawn.getPlayer());
addEquipmentLights(spawn.getPlayer());
}

@Subscribe
public void onPlayerChanged(PlayerChanged change) {
// Don't add spotanim lights on player change events, since it breaks death & respawn lights
Player player = change.getPlayer();
removeEquipmentLights(player);
addEquipmentLights(player);
}

@Subscribe
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/rs117/hd/scene/lights/Light.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class Light
public float[] origin = new float[3];
public float[] offset = new float[3];
public float[] pos = new float[3];
public float[] direction = new float[3];
public int orientation;
public float distanceSquared;

Expand All @@ -58,6 +59,7 @@ public class Light
public GraphicsObject graphicsObject;
public int tileObjectId;
public int spotanimId = -1;
public int equipmentItemId = -1;
public int[] projectileRefCounter;

public int sizeX = 1;
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/rs117/hd/scene/lights/LightDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@ public class LightDefinition {
public Alignment alignment = Alignment.CUSTOM;
public float[] offset = new float[3];
public int height;
public float heightFromModel = -1;
public int radius = 300;
public float strength = 5;
@JsonAdapter(ColorUtils.SrgbToLinearAdapter.class)
public float[] color;
public LightType type = LightType.STATIC;
public float duration;
public float range;
public float innerConeAngle = 0;
public float outerConeAngle = 0;
public float conePitch = 0;
public int fadeInDuration = 50;
public int fadeOutDuration = 50;
public int spawnDelay;
Expand All @@ -47,6 +51,8 @@ public class LightDefinition {
public HashSet<Integer> graphicsObjectIds = new HashSet<>();
@JsonAdapter(GamevalManager.AnimationAdapter.class)
public HashSet<Integer> animationIds = new HashSet<>();
@JsonAdapter(GamevalManager.ItemAdapter.class)
public HashSet<Integer> equipmentIds = new HashSet<>();

public void normalize() {
if (description == null)
Expand Down
Loading