mirror of
https://forgejo.xatacraft.ru/Sunshine/mkxp-sunshine.git
synced 2026-08-20 13:59:57 +00:00
DYNAMIC LIGHT OMG MEOW MEOW MEOW
This commit is contained in:
parent
6d95f72376
commit
e33ba85c03
33 changed files with 851 additions and 81 deletions
|
|
@ -4,7 +4,7 @@ include(FindPackageHandleStandardArgs)
|
|||
|
||||
# Options
|
||||
option(STEAM "Build for Steam" OFF)
|
||||
option(DEBUG "Debug mode" OFF)
|
||||
option(DEBUG "Debug mode" ON)
|
||||
option(NATIVE "Use native instructions(for local use only)" OFF)
|
||||
option(MODLOADER "Build with modloader" ON)
|
||||
|
||||
|
|
@ -77,6 +77,7 @@ set(MAIN_HEADERS
|
|||
src/meow.h
|
||||
src/modloader.h
|
||||
src/sunshine.h
|
||||
src/lightmap.h
|
||||
)
|
||||
|
||||
set(MAIN_SOURCE
|
||||
|
|
@ -122,6 +123,7 @@ set(MAIN_SOURCE
|
|||
src/meow.cpp
|
||||
src/modloader.cpp
|
||||
src/sunshine.cpp
|
||||
src/lightmap.cpp
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
|
|
@ -194,6 +196,7 @@ set(EMBEDDED_INPUT
|
|||
shader/simpleColor.frag
|
||||
shader/simpleAlpha.frag
|
||||
shader/simpleAlphaUni.frag
|
||||
shader/dynamicLight.frag
|
||||
shader/flashMap.frag
|
||||
shader/obscured.frag
|
||||
shader/minimal.vert
|
||||
|
|
@ -287,6 +290,7 @@ set(BINDING_SOURCE
|
|||
binding-mri/shader-binging.cpp
|
||||
binding-mri/modloader-binding.cpp
|
||||
binding-mri/keybindings-binding.cpp
|
||||
binding-mri/lightmap-binding.cpp
|
||||
)
|
||||
|
||||
source_group("Binding Source" FILES ${BINDING_SOURCE} ${BINDING_HEADERS})
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ void steamBindingInit();
|
|||
void shaderBindingInit();
|
||||
void ModLoaderBindingInit();
|
||||
void keybindingsBindingInit();
|
||||
void lightmapBindingInit();
|
||||
|
||||
RB_METHOD(mriPrint);
|
||||
RB_METHOD(mriP);
|
||||
|
|
@ -176,6 +177,7 @@ static void mriBindingInit(){
|
|||
shaderBindingInit();
|
||||
ModLoaderBindingInit();
|
||||
keybindingsBindingInit();
|
||||
lightmapBindingInit();
|
||||
|
||||
_rb_define_module_function(rb_mKernel, "rgss_main", mriRgssMain);
|
||||
_rb_define_module_function(rb_mKernel, "rgss_stop", mriRgssStop);
|
||||
|
|
|
|||
|
|
@ -273,8 +273,8 @@ DEF_PROP_OBJ_VAL(Bitmap, Font, Font, "font")
|
|||
RB_METHOD(bitmapGradientFillRect){
|
||||
Bitmap *b = getPrivateData<Bitmap>(self);
|
||||
|
||||
VALUE color1Obj, color2Obj;
|
||||
Color *color1, *color2;
|
||||
VALUE color1Obj, color2Obj, color3Obj, color4Obj;
|
||||
Color *color1, *color2, *color3, *color4;
|
||||
bool vertical = false;
|
||||
|
||||
if (argc == 3 || argc == 4){
|
||||
|
|
@ -289,7 +289,8 @@ RB_METHOD(bitmapGradientFillRect){
|
|||
color2 = getPrivateDataCheck<Color>(color2Obj, ColorType);
|
||||
|
||||
GUARD_EXC( b->gradientFillRect(rect->toIntRect(), color1->norm, color2->norm, vertical); );
|
||||
}else{
|
||||
}
|
||||
else if (argc == 6 || argc == 7){
|
||||
int x, y, width, height;
|
||||
|
||||
rb_get_args(argc, argv, "iiiioo|b", &x, &y, &width, &height,
|
||||
|
|
@ -300,21 +301,11 @@ RB_METHOD(bitmapGradientFillRect){
|
|||
|
||||
GUARD_EXC( b->gradientFillRect(x, y, width, height, color1->norm, color2->norm, vertical); );
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
RB_METHOD(bitmapGradientFillRect4){
|
||||
Bitmap *b = getPrivateData<Bitmap>(self);
|
||||
|
||||
VALUE color1Obj, color2Obj, color3Obj, color4Obj;
|
||||
Color *color1, *color2, *color3, *color4;
|
||||
|
||||
if (argc == 4 || argc == 5){
|
||||
else if (argc == 5){
|
||||
VALUE rectObj;
|
||||
Rect *rect;
|
||||
|
||||
rb_get_args(argc, argv, "ooo|b", &rectObj, &color1Obj, &color2Obj, &color3Obj, &color4Obj RB_ARG_END);
|
||||
rb_get_args(argc, argv, "ooooo", &rectObj, &color1Obj, &color2Obj, &color3Obj, &color4Obj RB_ARG_END);
|
||||
|
||||
rect = getPrivateDataCheck<Rect>(rectObj, RectType);
|
||||
color1 = getPrivateDataCheck<Color>(color1Obj, ColorType);
|
||||
|
|
@ -326,7 +317,7 @@ RB_METHOD(bitmapGradientFillRect4){
|
|||
}else{
|
||||
int x, y, width, height;
|
||||
|
||||
rb_get_args(argc, argv, "iiiioo|b", &x, &y, &width, &height, &color1Obj, &color2Obj, &color3Obj, &color4Obj RB_ARG_END);
|
||||
rb_get_args(argc, argv, "iiiioooo", &x, &y, &width, &height, &color1Obj, &color2Obj, &color3Obj, &color4Obj RB_ARG_END);
|
||||
|
||||
color1 = getPrivateDataCheck<Color>(color1Obj, ColorType);
|
||||
color2 = getPrivateDataCheck<Color>(color2Obj, ColorType);
|
||||
|
|
|
|||
95
binding-mri/lightmap-binding.cpp
Normal file
95
binding-mri/lightmap-binding.cpp
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
#include "lightmap.h"
|
||||
#include "disposable-binding.h"
|
||||
#include "flashable-binding.h"
|
||||
#include "sceneelement-binding.h"
|
||||
#include "viewportelement-binding.h"
|
||||
#include "binding-util.h"
|
||||
|
||||
DEF_TYPE(LightMap);
|
||||
|
||||
RB_METHOD(lightmapInitialize){
|
||||
LightMap *s = viewportElementInitialize<LightMap>(argc, argv, self);
|
||||
|
||||
setPrivateData(self, s);
|
||||
|
||||
/* Wrap property objects */
|
||||
s->initDynAttribs();
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
DEF_PROP_OBJ_REF(LightMap, Bitmap, WallMap, "wallmap")
|
||||
|
||||
DEF_PROP_I(LightMap, CameraX)
|
||||
DEF_PROP_I(LightMap, CameraY)
|
||||
DEF_PROP_I(LightMap, TilemapOffsetX)
|
||||
DEF_PROP_I(LightMap, TilemapOffsetY)
|
||||
|
||||
static VALUE clearStaticSources(VALUE self) {
|
||||
LightMap *k = getPrivateData<LightMap>(self);
|
||||
k->clearStaticLightSources();
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE clearDynamicSources(VALUE self) {
|
||||
LightMap *k = getPrivateData<LightMap>(self);
|
||||
k->clearDynamicLightSources();
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE addStaticSource(VALUE self, VALUE rb_x, VALUE rb_y, VALUE rb_power, VALUE rb_radius, VALUE rb_color) {
|
||||
LightMap *k = getPrivateData<LightMap>(self);
|
||||
Color *color;
|
||||
color = getPrivateDataCheck<Color>(rb_color, ColorType);
|
||||
k->addStaticLightSource( LightSource (
|
||||
NUM2DBL(rb_x),
|
||||
NUM2DBL(rb_y),
|
||||
NUM2DBL(rb_power),
|
||||
NUM2DBL(rb_radius),
|
||||
*color
|
||||
));
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE addDynamicSource(VALUE self, VALUE rb_x, VALUE rb_y, VALUE rb_power, VALUE rb_radius, VALUE rb_color) {
|
||||
LightMap *k = getPrivateData<LightMap>(self);
|
||||
Color *color;
|
||||
color = getPrivateDataCheck<Color>(rb_color, ColorType);
|
||||
k->addDynamicLightSource( LightSource (
|
||||
NUM2DBL(rb_x),
|
||||
NUM2DBL(rb_y),
|
||||
NUM2DBL(rb_power),
|
||||
NUM2DBL(rb_radius),
|
||||
*color
|
||||
));
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE setAmbient(VALUE self, VALUE var){
|
||||
LightMap *k = getPrivateData<LightMap>(self);
|
||||
k->setAmbient(NUM2DBL(var));
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
void lightmapBindingInit(){
|
||||
VALUE klass = rb_define_class("LightMap", rb_cObject);
|
||||
rb_define_alloc_func(klass, classAllocate<&LightMapType>);
|
||||
|
||||
disposableBindingInit <LightMap>(klass);
|
||||
flashableBindingInit <LightMap>(klass);
|
||||
viewportElementBindingInit<LightMap>(klass);
|
||||
|
||||
_rb_define_method(klass, "initialize", lightmapInitialize);
|
||||
|
||||
INIT_PROP_BIND( LightMap, WallMap, "wallmap" );
|
||||
INIT_PROP_BIND( LightMap, CameraX, "camera_x" );
|
||||
INIT_PROP_BIND( LightMap, CameraY, "camera_y" );
|
||||
INIT_PROP_BIND( LightMap, TilemapOffsetX, "tilemap_offset_x" );
|
||||
INIT_PROP_BIND( LightMap, TilemapOffsetY, "tilemap_offset_y" );
|
||||
|
||||
rb_define_method(klass, "clear_static_sources", clearStaticSources, 0);
|
||||
rb_define_method(klass, "clear_dynamic_sources", clearDynamicSources, 0);
|
||||
rb_define_method(klass, "add_static_source", addStaticSource, 5);
|
||||
rb_define_method(klass, "add_dynamic_source", addDynamicSource, 5);
|
||||
rb_define_method(klass, "ambient=", setAmbient, 1);
|
||||
}
|
||||
16
mklangsrc.rb
16
mklangsrc.rb
|
|
@ -47,6 +47,22 @@ module RPG
|
|||
end
|
||||
end
|
||||
class Table
|
||||
def each_with_index
|
||||
x = 0
|
||||
y = 0
|
||||
z = 0
|
||||
while z < self.sizez
|
||||
while y < self.sizey
|
||||
while x < self.sizex
|
||||
yield(self[x, y, z], x, y, z)
|
||||
x += 1
|
||||
end
|
||||
y += 1
|
||||
end
|
||||
z += 1
|
||||
end
|
||||
end
|
||||
|
||||
def self._load(foo)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -82,7 +82,8 @@ set(scripts
|
|||
i18n_Language.rb
|
||||
Window_TPtL.rb
|
||||
Settings.rb
|
||||
Input.rb)
|
||||
Input.rb
|
||||
DynamicLight.rb)
|
||||
|
||||
find_program(RUBY_EXE ruby
|
||||
DOC "Location of the Ruby executable")
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ module Settings
|
|||
:colorblind => false,
|
||||
:frameskip => true,
|
||||
:twm_shader => true,
|
||||
:light => true,
|
||||
:light_shadows => true,
|
||||
|
||||
# UI
|
||||
:in_game_timer => false,
|
||||
|
|
@ -153,6 +155,17 @@ class Window_Settings
|
|||
:name => tr('World machine shader'),
|
||||
:parameter => :twm_shader
|
||||
},
|
||||
{ :type => :sep, :name => tr("Lighting")},
|
||||
{
|
||||
:type => :bool,
|
||||
:name => tr('Dynamic Light'),
|
||||
:parameter => :light,
|
||||
},
|
||||
#{
|
||||
# :type => :bool,
|
||||
# :name => tr('Shadows'),
|
||||
# :parameter => :light_shadows
|
||||
#},
|
||||
],
|
||||
tr("UI") => [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class Window_Settings
|
|||
|
||||
@selection_sprite = Sprite.new(@viewport)
|
||||
@selection_sprite.bitmap = Bitmap.new(PARAMETER_WIDTH + 16, PARAMETER_HEIGHT)
|
||||
@selection_sprite.bitmap.fill_rect(Rect.new(0, 0, PARAMETER_WIDTH + 16, PARAMETER_HEIGHT), Color.new(255, 255, 255, 64))
|
||||
@selection_sprite.bitmap.fill_rect(Rect.new(0, 0, PARAMETER_WIDTH + 16, PARAMETER_HEIGHT), Color.new(255, 255, 255, 128))
|
||||
@selection_sprite.x = @x - 8
|
||||
@selection_sprite.y = @offset
|
||||
@selection_sprite.opacity = 0
|
||||
|
|
@ -46,6 +46,7 @@ class Window_Settings
|
|||
@screen_panel_selection_sprite.bitmap.gradient_fill_rect(0, 0, @screen_panel_selection_sprite.bitmap.width, @screen_panel_selection_sprite.bitmap.height, Color.new(255, 255, 255, 0), Color.new(255, 255, 255, 128), true)
|
||||
@screen_panel_selection_sprite.y = SCREENS_PANELS_MARGIN + SCREENS_PANELS_TOP_MARGIN
|
||||
@screen_panel_selection_sprite.x = Graphics.width / 2
|
||||
@screen_panel_selection_sprite.blend_type = 1
|
||||
|
||||
@switch_panels_hint_left = Sprite.new(@viewport)
|
||||
@switch_panels_hint_left.bitmap = Bitmap.new(PARAMETER_WIDTH / 2 - SCREENS_PANELS_MARGIN, @screen_panel_selection_sprite.height / 2)
|
||||
|
|
@ -61,6 +62,7 @@ class Window_Settings
|
|||
@switch_panels_hint_left.zoom_x = @switch_panels_hint_right.zoom_x =
|
||||
@switch_panels_hint_left.zoom_y = @switch_panels_hint_right.zoom_y = 2
|
||||
@switch_panels_hint_left.opacity = @switch_panels_hint_right.opacity = 127
|
||||
@switch_panels_hint_left.blend_type = @switch_panels_hint_right.blend_type = 1
|
||||
|
||||
redraw_panels_hints
|
||||
|
||||
|
|
|
|||
123
scripts/DynamicLight.rb
Normal file
123
scripts/DynamicLight.rb
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
class DynamicLight
|
||||
attr_accessor :done
|
||||
attr_accessor :plr_light_power
|
||||
attr_accessor :plr_light_color
|
||||
|
||||
def initialize(viewport)
|
||||
@done = false # for events
|
||||
@awaked = false
|
||||
|
||||
@light_npc = []
|
||||
|
||||
@ambient_light = 255
|
||||
@ambient_light_lerped = 255
|
||||
|
||||
@plr_light_power = 0
|
||||
@plr_light_radius = -1.0
|
||||
@plr_light_radius_lerped = 5.0
|
||||
@plr_light_color = Color.new(255, 255, 255)
|
||||
|
||||
@light_sprite = LightMap.new(viewport)
|
||||
@light_sprite.wallmap = Bitmap.new($game_map.width, $game_map.height)
|
||||
|
||||
for x in 0...$game_map.width
|
||||
for y in 0...$game_map.height
|
||||
@light_sprite.wallmap.set_pixel(x, y, Color.new(
|
||||
b(light_passable($game_map.data[x, y, 0])),
|
||||
b(light_passable($game_map.data[x, y, 1])),
|
||||
b(light_passable($game_map.data[x, y, 2]))
|
||||
))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def dispose
|
||||
@light_sprite.dispose
|
||||
end
|
||||
|
||||
def update
|
||||
@plr_light_radius_lerped = @plr_light_radius_lerped * 0.8 + @plr_light_radius * 0.2
|
||||
|
||||
@light_sprite.visible = Settings[:light] && @awaked
|
||||
if (!Settings[:light] && @awaked)
|
||||
return
|
||||
end
|
||||
|
||||
@light_sprite.camera_x = $game_map.display_x / 4
|
||||
@light_sprite.camera_y = $game_map.display_y / 4
|
||||
@light_sprite.tilemap_offset_x = ($game_map.display_x / 128) * 32 - $game_map.display_x / 4
|
||||
@light_sprite.tilemap_offset_y = ($game_map.display_y / 128) * 32 - $game_map.display_y / 4
|
||||
|
||||
@light_sprite.clear_dynamic_sources()
|
||||
plr_light = [$game_player.real_x / 128.0, $game_player.real_y / 128.0, @plr_light_power, @plr_light_radius_lerped, @plr_light_color]
|
||||
if has_effect(plr_light)
|
||||
@light_sprite.add_dynamic_source(plr_light[0], plr_light[1] - 0.5, plr_light[2], plr_light[3], plr_light[4])
|
||||
end
|
||||
|
||||
@light_npc.each { |npc_light_source|
|
||||
npc_light = [npc_light_source[0].real_x / 128.0, npc_light_source[0].real_y / 128.0, npc_light_source[1], npc_light_source[2], npc_light_source[3]]
|
||||
if has_effect(npc_light)
|
||||
@light_sprite.add_dynamic_source(npc_light[0], npc_light[1] - 0.5, npc_light[2], npc_light[3], npc_light[4])
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
def light_passable(tile_id)
|
||||
$game_map.passages[tile_id] & 15 == 0
|
||||
end
|
||||
|
||||
def b(val)
|
||||
val ? 255 : 0
|
||||
end
|
||||
|
||||
def add(x, y, power, radius, color = Color.new(255, 255, 255))
|
||||
@awaked = true
|
||||
@light_sprite.add_static_source(x, y, power, radius, color)
|
||||
end
|
||||
|
||||
def add_npc(npc_id, power, radius, color = Color.new(255, 255, 255))
|
||||
@awaked = true
|
||||
@light_npc << [$game_map.events[npc_id], power, radius, color]
|
||||
end
|
||||
|
||||
def has_effect(source)
|
||||
source[2] > 0 && source[3] > 0 && source[4].alpha >= 0 && (source[4].red > 0 || source[4].green > 0 || source[4].blue > 0)
|
||||
end
|
||||
|
||||
#def remove(x, y)
|
||||
# @light_sources.each do |sourse|
|
||||
# if sourse[0] == x && sourse[1] == y
|
||||
# @light_sources.delete(sourse)
|
||||
# return true
|
||||
# end
|
||||
# end
|
||||
# return false
|
||||
#end
|
||||
|
||||
def awake
|
||||
@awaked = true
|
||||
end
|
||||
|
||||
def sleep # fully disables dynamic light system
|
||||
@awaked = false
|
||||
end
|
||||
|
||||
def ambient_light
|
||||
@ambient_light
|
||||
end
|
||||
def ambient_light=(val)
|
||||
@ambient_light = val
|
||||
@light_sprite.ambient = val
|
||||
@awaked = true
|
||||
end
|
||||
|
||||
def plr_light_radius
|
||||
@plr_light_radius
|
||||
end
|
||||
def plr_light_radius=(val)
|
||||
if @plr_light_radius < 0
|
||||
@plr_light_radius_lerped = val
|
||||
end
|
||||
@plr_light_radius = val
|
||||
end
|
||||
end
|
||||
|
|
@ -241,13 +241,13 @@ class Game_Event < Game_Character
|
|||
def update
|
||||
super
|
||||
|
||||
if(@made_text == false && @event.name.start_with?("@text"))
|
||||
if @list.size > 1 && @list[0].code == 101
|
||||
if(@made_text == false && @event.name.start_with?("@text"))
|
||||
if @list.size > 1 && @list[0].code == 101
|
||||
$scene.new_maptext(Language.tr(@list[0].parameters[0].strip), @x, @y)
|
||||
@list.delete_at(0)
|
||||
@list.delete_at(0)
|
||||
end
|
||||
@made_text = true
|
||||
end
|
||||
@made_text = true
|
||||
end
|
||||
# Automatic event starting determinant
|
||||
check_event_trigger_auto
|
||||
# If parallel process is valid
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ class Game_Map
|
|||
# distance : scroll distance
|
||||
#--------------------------------------------------------------------------
|
||||
def scroll_down(distance)
|
||||
if self.height < Graphics.height / 28
|
||||
if self.height < Graphics.height / 28
|
||||
@display_y = self.height / 2
|
||||
else
|
||||
@display_y = [@display_y + distance, (self.height - Graphics.height / 28) * 128].min
|
||||
|
|
@ -289,10 +289,10 @@ class Game_Map
|
|||
# distance : scroll distance
|
||||
#--------------------------------------------------------------------------
|
||||
def scroll_up(distance)
|
||||
if self.height < Graphics.height / 28
|
||||
@display_y = self.height / 2
|
||||
if self.height < Graphics.height / 28
|
||||
@display_y = self.height / 2
|
||||
else
|
||||
@display_y = [@display_y - distance, 0].max
|
||||
@display_y = [@display_y - distance, 0].max
|
||||
end
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -8,4 +8,35 @@ module Input
|
|||
return normalized < Settings[:gamepad_deadzone] / 10.0 ? 0.0 : normalized
|
||||
end
|
||||
end
|
||||
|
||||
GAMEPAD_BUTTONS_NAMES = {
|
||||
"a" => "A", # ▲□Ο
|
||||
"b" => "B",
|
||||
"x" => "X",
|
||||
"y" => "Y",
|
||||
"lefttringger" => "LT",
|
||||
"righttringger" => "RT",
|
||||
"leftshoulder" => "LS",
|
||||
"rightshoulder" => "RS",
|
||||
"dpdown" => "D-Pad Down",
|
||||
"dpleft" => "D-Pad Left",
|
||||
"dpright" => "D-Pad Right",
|
||||
"dpup" => "D-Pad Up",
|
||||
"back" => "Back",
|
||||
"guide" => "Guide",
|
||||
"start" => "Start",
|
||||
"leftstick" => "Left Stick",
|
||||
"rightstick" => "Right Stick",
|
||||
"leftpaddle1" => "Left Paddle 1",
|
||||
"rightpaddle1" => "Right Paddle 1",
|
||||
"leftpaddle2" => "Left Paddle 2",
|
||||
"rightpaddle2" => "Right Paddle 2",
|
||||
"touchpad" => "Touchpad",
|
||||
"misc1" => "Misc 1",
|
||||
"misc2" => "Misc 2",
|
||||
"misc3" => "Misc 3",
|
||||
"misc4" => "Misc 4",
|
||||
"misc5" => "Misc 5",
|
||||
"misc6" => "Misc 6",
|
||||
}
|
||||
end
|
||||
|
|
@ -438,22 +438,22 @@ class Scene_Map
|
|||
def new_footprint(direction, x, y)
|
||||
if @spriteset != nil
|
||||
@spriteset.new_footprint(direction, x, y)
|
||||
end
|
||||
end
|
||||
end
|
||||
def new_footsplash(direction, x, y)
|
||||
if @spriteset != nil
|
||||
@spriteset.new_footsplash(direction, x, y)
|
||||
end
|
||||
end
|
||||
end
|
||||
def new_maptext(text, x, y)
|
||||
if @spriteset != nil
|
||||
@spriteset.new_maptext(text, x, y)
|
||||
end
|
||||
end
|
||||
end
|
||||
def fix_footsplashes(xDelt, yDelt)
|
||||
if @spriteset != nil
|
||||
@spriteset.fix_footsplashes(xDelt, yDelt)
|
||||
end
|
||||
end
|
||||
end
|
||||
def menu_open?
|
||||
@menu.visible || @item_menu.visible
|
||||
|
|
|
|||
|
|
@ -78,13 +78,16 @@ class Spriteset_Map
|
|||
@timer_sprite = Sprite_Timer.new
|
||||
# Make lightbulb sprite
|
||||
@bulb = Sprite.new(@viewport_lights)
|
||||
@bulb.x = 0
|
||||
if Graphics.width == 1280
|
||||
@bulb.bitmap = RPG::Cache.light('bulb_16')
|
||||
else
|
||||
@bulb.bitmap = RPG::Cache.light('bulb')
|
||||
end
|
||||
@bulb.x = 0
|
||||
if Graphics.width == 1280
|
||||
@bulb.bitmap = RPG::Cache.light('bulb_16')
|
||||
else
|
||||
@bulb.bitmap = RPG::Cache.light('bulb')
|
||||
end
|
||||
@bulb.opacity = has_lightbulb? ? 255 : 0
|
||||
# Make dynamic light
|
||||
@dynamic_light = DynamicLight.new(@viewport_lights)
|
||||
$light = @dynamic_light
|
||||
# Panorama animation timer
|
||||
@pan_animate_timer = 0
|
||||
RPG::Mod.exec_hooks("hooks/Spriteset_Map/init", binding)
|
||||
|
|
@ -116,6 +119,8 @@ class Spriteset_Map
|
|||
@footprint_sprites.each do |sprite|
|
||||
sprite.dispose
|
||||
end
|
||||
# Dispose of dynamic light
|
||||
@dynamic_light.dispose
|
||||
# Dispose of weather
|
||||
@weather.dispose
|
||||
# Dispose of picture sprites
|
||||
|
|
@ -264,9 +269,9 @@ class Spriteset_Map
|
|||
@tilemap.oy = $game_map.display_y / 4
|
||||
@tilemap.update
|
||||
# Update panorama plane
|
||||
if $game_map.always_moving
|
||||
$game_map.pan_move_offset += 1
|
||||
end
|
||||
if $game_map.always_moving
|
||||
$game_map.pan_move_offset += 1
|
||||
end
|
||||
if $game_map.clamped_x
|
||||
x = ($game_player.real_x.to_f / (($game_map.width - 1) * 128)) * (@panorama.bitmap.width * $game_map.pan_zoom - Graphics.width)
|
||||
@panorama.ox = x < 0.0 ? 0.0 : x
|
||||
|
|
@ -318,25 +323,15 @@ class Spriteset_Map
|
|||
@character_sprites.each do |sprite|
|
||||
if !sprite.character.is_a?(Game_Event)
|
||||
sprite.update
|
||||
elsif
|
||||
|
||||
# this is just a check to make sure the sprite is onscreen for game events
|
||||
# based on its current width and height
|
||||
# no point in updating the sprite if offscreen
|
||||
# this greatly increases performance on larger maps
|
||||
if Graphics.width == 1280
|
||||
((sprite.character.real_x + (sprite.ox*4) > Graphics.width - 128) &&
|
||||
(sprite.character.real_x - (sprite.ox*4) < Graphics.width + (21 * 128)) &&
|
||||
(sprite.character.real_y + (sprite.oy*4) > (Graphics.height) - 128) &&
|
||||
(sprite.character.real_y - (sprite.oy*4) < (Graphics.height) + (17 * 128)))
|
||||
sprite.update
|
||||
else
|
||||
((sprite.character.real_x + (sprite.ox*4) > Graphics.width - 128) &&
|
||||
(sprite.character.real_x - (sprite.ox*4) < Graphics.width + (10 * 128)) &&
|
||||
(sprite.character.real_y + (sprite.oy*4) > (Graphics.height) - 128) &&
|
||||
(sprite.character.real_y - (sprite.oy*4) < (Graphics.height) + (6 * 128)))
|
||||
sprite.update
|
||||
end
|
||||
elsif ((sprite.character.real_x + (sprite.ox*4) > $game_map.display_x - 128) &&
|
||||
(sprite.character.real_x - (sprite.ox*4) < $game_map.display_x + ((Graphics.width / 32 + 1) * 128)) &&
|
||||
(sprite.character.real_y + (sprite.oy*4) > ($game_map.display_y) - 128) &&
|
||||
(sprite.character.real_y - (sprite.oy*4) < ($game_map.display_y) + (Graphics.height / 32 * 128)))
|
||||
sprite.update
|
||||
else
|
||||
sprite.update_fast
|
||||
end
|
||||
|
|
@ -367,6 +362,8 @@ class Spriteset_Map
|
|||
@bulb.opacity -= 2.125
|
||||
end
|
||||
end
|
||||
|
||||
@dynamic_light.update
|
||||
# Update particles
|
||||
@particles.update if @particles
|
||||
# Update timer sprite
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ Doc_Message
|
|||
Desktop_Message
|
||||
Credits_Message
|
||||
Particles
|
||||
DynamicLight
|
||||
|
||||
EdText
|
||||
Main
|
||||
|
|
|
|||
42
shader/dynamicLight.frag
Normal file
42
shader/dynamicLight.frag
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
uniform vec4 lightSources[64];
|
||||
uniform vec4 lightSourcesColors[64];
|
||||
uniform int lightSourcesCount;
|
||||
uniform float ambientLight;
|
||||
|
||||
uniform sampler2D texture;
|
||||
uniform sampler2D wallMapTexture;
|
||||
|
||||
uniform vec2 wallMapResolution;
|
||||
|
||||
uniform vec2 cameraPosition;
|
||||
uniform vec2 tileMapOffset;
|
||||
|
||||
uniform vec2 texSizeInv;
|
||||
varying vec2 v_texCoord;
|
||||
|
||||
const vec2 tileSize = vec2(32, 32);
|
||||
const float powerBase = 255.0;
|
||||
|
||||
float distance(vec2 a, vec2 b){
|
||||
vec2 c = a - b;
|
||||
return sqrt(c.x * c.x + c.y * c.y);
|
||||
}
|
||||
|
||||
void main(){
|
||||
vec2 screenPoint = v_texCoord / texSizeInv;
|
||||
vec2 mapPoint = cameraPosition + screenPoint;
|
||||
vec2 wallmapUV = mapPoint / tileSize / wallMapResolution;
|
||||
|
||||
vec3 light = vec3(0, 0, 0);
|
||||
|
||||
for(int i = 0; i < lightSourcesCount; i++) {
|
||||
vec4 sourceInfo = lightSources[i];
|
||||
vec4 sourceColor = lightSourcesColors[i];
|
||||
vec2 lightScreenPoint = (sourceInfo.xy - cameraPosition / tileSize) * tileSize + tileSize / 2.0;
|
||||
light += sourceInfo.z / powerBase *
|
||||
sourceColor.rgb *
|
||||
pow(clamp(1.0 - distance(screenPoint, lightScreenPoint) / 32.0 / sourceInfo.w, 0.0, 1.0), sourceColor.a * 2.0);
|
||||
}
|
||||
|
||||
gl_FragColor = vec4(light + ambientLight / powerBase, 1.0);
|
||||
}
|
||||
|
|
@ -48,8 +48,10 @@ void main(){
|
|||
float noise2 = pnoise(uv2 + vec2(WATER_DISTORTION, -WATER_DISTORTION) * noise);
|
||||
float p2 = pow(noise2 + 0.2, 10.0);
|
||||
|
||||
vec4 frag = mix(vec4(waterColor1.rgb, 1.0), vec4(waterColor2.rgb, 1.0), noise1) + vec4(vec3(mix(p, 1.0, textureColor.r)) * waterColor3.rgb, 1.0);
|
||||
frag += mix(vec4(waterColor1.rgb, 1.0), vec4(waterColor2.rgb, 1.0), noise2) + vec4(vec3(mix(p2, 1.0, textureColor.r)) * waterColor3.rgb, 1.0);
|
||||
vec4 frag = mix(vec4(waterColor1.rgb, 1.0), vec4(waterColor2.rgb, 1.0), noise1) + vec4(vec3(mix(p, 1.0, textureColor.r)) * waterColor3.rgb, 0.0);
|
||||
frag += mix(vec4(waterColor1.rgb, 1.0), vec4(waterColor2.rgb, 1.0), noise2) + vec4(vec3(mix(p2, 1.0, textureColor.r)) * waterColor3.rgb, 0.0);
|
||||
frag.a = clamp(frag.a / 2.0, 0.0, 1.0);
|
||||
frag.rgb = clamp(frag.rgb, vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0));
|
||||
|
||||
float isWater = float(
|
||||
waterColorCheck == vec4(1, 0, 0, 1)
|
||||
|
|
|
|||
|
|
@ -40,7 +40,9 @@ void main(){
|
|||
float p2 = pow(noise2 + 0.02, 20.0);
|
||||
|
||||
vec4 frag = mix(vec4(color.r, color.g, color.b, 1.0) * color.a, vec4(color.r, color.g, color.b, 1.0) * tone.a, noise1) + vec4(p, p, p, 1.0) * tone;
|
||||
frag += mix(vec4(color.r, color.g, color.b, 1.0) * color.a, vec4(color.r, color.g, color.b, 1.0) * tone.a, noise2) + vec4(p2, p2, p2, 1.0) * tone;
|
||||
frag += mix(vec4(color.r, color.g, color.b, 1.0) * color.a, vec4(color.r, color.g, color.b, 1.0) * tone.a, noise2) + vec4(p2, p2, p2, 1.0) * tone;
|
||||
frag.a = clamp(frag.a / 2.0, 0.0, 1.0);
|
||||
frag.rgb = clamp(frag.rgb, vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0));
|
||||
|
||||
/* Apply opacity */
|
||||
frag.a *= opacity;
|
||||
|
|
|
|||
|
|
@ -770,6 +770,11 @@ void Bitmap::setPixel(int x, int y, const Color &color){
|
|||
|
||||
GUARD_MEGA;
|
||||
|
||||
if (x < 0 || y < 0 || x >= width() || y >= height()) {
|
||||
Debug() << "Invalid pixel position " << x << " " << y << " in bitmap " << width() << "x" << height();
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t pixel[] = {
|
||||
(uint8_t) clamp<double>(color.red, 0, 255),
|
||||
(uint8_t) clamp<double>(color.green, 0, 255),
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "disposable.h"
|
||||
#include "etc-internal.h"
|
||||
#include "etc.h"
|
||||
#include "debugwriter.h"
|
||||
|
||||
// #include <sigc++/signal.h>
|
||||
#include <sigc++/signal.h>
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ public:
|
|||
#elif __EMSCRIPTEN__
|
||||
emscripten_console_log(buf.str().c_str());
|
||||
#else
|
||||
std::cerr << buf.str() << "\n";
|
||||
std::cout << buf.str() << "\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,22 @@ struct Vec4{
|
|||
}
|
||||
};
|
||||
|
||||
struct Vec4i{
|
||||
int x, y, z, w;
|
||||
|
||||
Vec4i()
|
||||
: x(0), y(0), z(0), w(0)
|
||||
{}
|
||||
|
||||
Vec4i(int x, int y, int z, int w)
|
||||
: x(x), y(y), z(z), w(w)
|
||||
{}
|
||||
|
||||
bool operator==(const Vec4i &other) const{
|
||||
return (x == other.x && y == other.y && z == other.z && w == other.w);
|
||||
}
|
||||
};
|
||||
|
||||
struct Vec2i{
|
||||
int x, y;
|
||||
|
||||
|
|
|
|||
|
|
@ -68,17 +68,17 @@ void Color::set(double red, double green, double blue, double alpha){
|
|||
|
||||
void Color::setRed(double value){
|
||||
red = value;
|
||||
norm.x = clamp<double>(value, 0, 255) / 255;
|
||||
norm.x = value / 255;
|
||||
}
|
||||
|
||||
void Color::setGreen(double value){
|
||||
green = value;
|
||||
norm.y = clamp<double>(value, 0, 255) / 255;
|
||||
norm.y = value / 255;
|
||||
}
|
||||
|
||||
void Color::setBlue(double value){
|
||||
blue = value;
|
||||
norm.z = clamp<double>(value, 0, 255) / 255;
|
||||
norm.z = value / 255;
|
||||
}
|
||||
|
||||
void Color::setAlpha(double value){
|
||||
|
|
|
|||
24
src/etc.h
24
src/etc.h
|
|
@ -34,7 +34,8 @@ enum BlendType{
|
|||
|
||||
BlendNormal = 0,
|
||||
BlendAddition = 1,
|
||||
BlendSubstraction = 2
|
||||
BlendSubstraction = 2,
|
||||
BlendMultiply = 3
|
||||
};
|
||||
|
||||
struct Color : public Serializable{
|
||||
|
|
@ -192,6 +193,27 @@ struct Rect : public Serializable{
|
|||
sigc::signal<void> valueChanged;
|
||||
};
|
||||
|
||||
|
||||
struct LightSource {
|
||||
float x;
|
||||
float y;
|
||||
float power;
|
||||
float radius;
|
||||
Color color;
|
||||
|
||||
LightSource()
|
||||
: x(0), y(0), power(0), radius(0), color(Color())
|
||||
{};
|
||||
|
||||
LightSource(float x, float y, float power, float radius, Color color)
|
||||
: x(x), y(y), power(power), radius(radius), color(color)
|
||||
{};
|
||||
|
||||
bool hasEffect(){
|
||||
return radius > 0.0 && power > 0.0 && color.alpha >= 0.0 && (color.red > 0.0 || color.green > 0.0 || color.blue > 0.0);
|
||||
}
|
||||
};
|
||||
|
||||
/* For internal use.
|
||||
* All drawable classes have properties of one or more of the above
|
||||
* types, which in an interpreted environment act as independent
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ typedef void (APIENTRYP _PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);
|
|||
typedef void (APIENTRYP _PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1);
|
||||
typedef void (APIENTRYP _PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
|
||||
typedef void (APIENTRYP _PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
|
||||
typedef void (APIENTRYP _PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
|
||||
typedef void (APIENTRYP _PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
|
||||
/* Vertex attribute */
|
||||
|
|
@ -174,6 +175,7 @@ typedef void (APIENTRYP _PFNGLRELEASESHADERCOMPILERPROC) (void);
|
|||
GL_FUN(Uniform2f, _PFNGLUNIFORM2FPROC) \
|
||||
GL_FUN(Uniform4f, _PFNGLUNIFORM4FPROC) \
|
||||
GL_FUN(Uniform1i, _PFNGLUNIFORM1IPROC) \
|
||||
GL_FUN(Uniform4i, _PFNGLUNIFORM4IPROC) \
|
||||
GL_FUN(UniformMatrix4fv, _PFNGLUNIFORMMATRIX4FVPROC) \
|
||||
/* Vertex attribute */ \
|
||||
GL_FUN(BindAttribLocation, _PFNGLBINDATTRIBLOCATIONPROC) \
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ namespace TEX{
|
|||
}
|
||||
|
||||
static inline void uploadImage(GLsizei width, GLsizei height, const void *data, GLenum format){
|
||||
gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, GL_UNSIGNED_BYTE, data);
|
||||
gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, format, GL_UNSIGNED_BYTE, data);
|
||||
}
|
||||
|
||||
static inline void uploadSubImage(GLint x, GLint y, GLsizei width, GLsizei height, const void *data, GLenum format){
|
||||
|
|
@ -80,7 +80,7 @@ namespace TEX{
|
|||
}
|
||||
|
||||
static inline void allocEmpty(GLsizei width, GLsizei height){
|
||||
gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_HALF_FLOAT, 0);
|
||||
}
|
||||
|
||||
static inline void setRepeat(bool mode){
|
||||
|
|
@ -217,4 +217,10 @@ struct TEXFBO{
|
|||
}
|
||||
};
|
||||
|
||||
#define GL_CHECK() { \
|
||||
GLenum e = gl.GetError(); \
|
||||
if (e != GL_NO_ERROR) \
|
||||
printf("%s:%d -> %x\n", __FILE__, __LINE__, e); \
|
||||
}
|
||||
|
||||
#endif // GLUTIL_H
|
||||
|
|
|
|||
|
|
@ -82,6 +82,12 @@ void GLBlendMode::apply(const BlendType &value){
|
|||
gl.BlendFuncSeparate(GL_SRC_ALPHA, GL_ONE,
|
||||
GL_ONE, GL_ONE);
|
||||
break;
|
||||
|
||||
case BlendMultiply :
|
||||
gl.BlendEquation(GL_FUNC_ADD);
|
||||
gl.BlendFuncSeparate(GL_DST_COLOR, GL_ZERO,
|
||||
GL_ZERO, GL_ONE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
256
src/lightmap.cpp
Normal file
256
src/lightmap.cpp
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
#include "lightmap.h"
|
||||
|
||||
#include "sharedstate.h"
|
||||
#include "bitmap.h"
|
||||
#include "etc.h"
|
||||
#include "etc-internal.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "gl-util.h"
|
||||
#include "quad.h"
|
||||
#include "transform.h"
|
||||
#include "shader.h"
|
||||
#include "glstate.h"
|
||||
#include "quadarray.h"
|
||||
#include "config.h"
|
||||
#include "debugwriter.h"
|
||||
#include "sunshine.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <SDL3/SDL_rect.h>
|
||||
|
||||
#include <sigc++/connection.h>
|
||||
#include <boost/chrono.hpp>
|
||||
|
||||
struct LightMapPrivate{
|
||||
|
||||
Bitmap *bitmap;
|
||||
Bitmap *wallMap;
|
||||
|
||||
int cameraX, cameraY, tilemapOffsetX, tilemapOffsetY;
|
||||
float ambient;
|
||||
std::vector<LightSource> staticLightSources;
|
||||
std::vector<LightSource> dynamicLightSources;
|
||||
std::vector<LightSource> gpuBuffer;
|
||||
|
||||
Quad quad;
|
||||
Transform trans;
|
||||
|
||||
Rect *srcRect;
|
||||
sigc::connection srcRectCon;
|
||||
|
||||
IntRect sceneRect;
|
||||
Vec2i sceneOrig;
|
||||
|
||||
/* Would this sprite be visible on
|
||||
* the screen if drawn? */
|
||||
bool isVisible;
|
||||
|
||||
EtcTemps tmp;
|
||||
|
||||
sigc::connection prepareCon;
|
||||
|
||||
LightMapPrivate()
|
||||
: bitmap(new Bitmap(shState->graphics().width(), shState->graphics().height())),
|
||||
wallMap(0),
|
||||
cameraX(0),
|
||||
cameraY(0),
|
||||
tilemapOffsetX(0),
|
||||
tilemapOffsetY(0),
|
||||
ambient(255.0),
|
||||
srcRect(&tmp.rect),
|
||||
isVisible(false)
|
||||
|
||||
{
|
||||
sceneRect.x = sceneRect.y = 0;
|
||||
|
||||
updateSrcRectCon();
|
||||
|
||||
prepareCon = shState->prepareDraw.connect(sigc::mem_fun(this, &LightMapPrivate::prepare));
|
||||
|
||||
bitmap->ensureNonMega();
|
||||
//bitmap->fillRect(0, 0, shState->graphics().width(), shState->graphics().height(), Vec4(0, 0, 0, 1));
|
||||
|
||||
staticLightSources.reserve(48);
|
||||
dynamicLightSources.reserve(16);
|
||||
gpuBuffer.reserve(64);
|
||||
}
|
||||
|
||||
~LightMapPrivate(){
|
||||
srcRectCon.disconnect();
|
||||
prepareCon.disconnect();
|
||||
}
|
||||
|
||||
void onSrcRectChange(){
|
||||
FloatRect rect = srcRect->toFloatRect();
|
||||
Vec2i bmSize;
|
||||
|
||||
if (!nullOrDisposed(bitmap))
|
||||
bmSize = Vec2i(bitmap->width(), bitmap->height());
|
||||
|
||||
/* Clamp the rectangle so it doesn't reach outside
|
||||
* the bitmap bounds */
|
||||
rect.w = clamp<int>(rect.w, 0, bmSize.x-rect.x);
|
||||
rect.h = clamp<int>(rect.h, 0, bmSize.y-rect.y);
|
||||
|
||||
quad.setTexRect(rect);
|
||||
|
||||
quad.setPosRect(FloatRect(0, 0, rect.w, rect.h));
|
||||
}
|
||||
|
||||
void updateSrcRectCon(){
|
||||
/* Cut old connection */
|
||||
srcRectCon.disconnect();
|
||||
/* Create new one */
|
||||
srcRectCon = srcRect->valueChanged.connect(sigc::mem_fun(this, &LightMapPrivate::onSrcRectChange));
|
||||
}
|
||||
|
||||
void updateVisibility(){
|
||||
isVisible = false;
|
||||
|
||||
if (nullOrDisposed(bitmap))
|
||||
return;
|
||||
|
||||
/* Compare sprite bounding box against the scene */
|
||||
|
||||
/* If sprite is zoomed/rotated, just opt out for now
|
||||
* for simplicity's sake */
|
||||
const Vec2 &scale = trans.getScale();
|
||||
if (scale.x != 1 || scale.y != 1 || trans.getRotation() != 0){
|
||||
isVisible = true;
|
||||
return;
|
||||
}
|
||||
|
||||
IntRect self;
|
||||
self.setPos(trans.getPositionI() - (trans.getOriginI() + sceneOrig));
|
||||
self.w = bitmap->width();
|
||||
self.h = bitmap->height();
|
||||
|
||||
isVisible = SDL_HasRectIntersection(&self, &sceneRect);
|
||||
}
|
||||
|
||||
void prepare(){
|
||||
updateVisibility();
|
||||
}
|
||||
};
|
||||
|
||||
LightMap::LightMap(Viewport *viewport)
|
||||
: ViewportElement(viewport){
|
||||
p = new LightMapPrivate;
|
||||
onGeometryChange(scene->getGeometry());
|
||||
|
||||
if (nullOrDisposed(p->bitmap))
|
||||
return;
|
||||
|
||||
p->bitmap->ensureNonMega();
|
||||
|
||||
*p->srcRect = p->bitmap->rect();
|
||||
p->onSrcRectChange();
|
||||
p->quad.setPosRect(p->srcRect->toFloatRect());
|
||||
}
|
||||
|
||||
LightMap::~LightMap(){
|
||||
dispose();
|
||||
}
|
||||
|
||||
DEF_ATTR_RD_SIMPLE(LightMap, WallMap, Bitmap*, p->wallMap)
|
||||
|
||||
DEF_ATTR_SIMPLE(LightMap, CameraX, int, p->cameraX)
|
||||
DEF_ATTR_SIMPLE(LightMap, CameraY, int, p->cameraY)
|
||||
DEF_ATTR_SIMPLE(LightMap, TilemapOffsetX, int, p->tilemapOffsetX)
|
||||
DEF_ATTR_SIMPLE(LightMap, TilemapOffsetY, int, p->tilemapOffsetY)
|
||||
|
||||
DEF_ATTR_SIMPLE(LightMap, Ambient, float, p->ambient);
|
||||
|
||||
void LightMap::setWallMap(Bitmap *bitmap){
|
||||
guardDisposed();
|
||||
|
||||
if (p->wallMap == bitmap)
|
||||
return;
|
||||
|
||||
p->wallMap = bitmap;
|
||||
|
||||
if (nullOrDisposed(bitmap))
|
||||
return;
|
||||
|
||||
bitmap->ensureNonMega();
|
||||
}
|
||||
|
||||
void LightMap::initDynAttribs(){
|
||||
p->srcRect = new Rect;
|
||||
|
||||
p->updateSrcRectCon();
|
||||
}
|
||||
|
||||
/* Flashable */
|
||||
void LightMap::update(){
|
||||
guardDisposed();
|
||||
|
||||
Flashable::update();
|
||||
}
|
||||
|
||||
void LightMap::clearStaticLightSources(){
|
||||
p->staticLightSources.clear();
|
||||
}
|
||||
void LightMap::clearDynamicLightSources(){
|
||||
p->dynamicLightSources.clear();
|
||||
}
|
||||
void LightMap::addStaticLightSource(LightSource source){
|
||||
p->staticLightSources.push_back(source);
|
||||
}
|
||||
void LightMap::addDynamicLightSource(LightSource source){
|
||||
p->dynamicLightSources.push_back(source);
|
||||
}
|
||||
|
||||
/* SceneElement */
|
||||
void LightMap::draw(){
|
||||
if (!p->isVisible)
|
||||
return;
|
||||
|
||||
if (emptyFlashFlag)
|
||||
return;
|
||||
|
||||
DynamicLightShader &shader = shState->shaders().dynamicLight;
|
||||
shader.bind();
|
||||
shader.applyViewportProj();
|
||||
|
||||
if (p->wallMap)
|
||||
shader.setWallMapTexture(p->wallMap->getGLTypes().tex);
|
||||
shader.setWallMapResolution(p->wallMap->width(), p->wallMap->height());
|
||||
shader.setCameraPosition(p->cameraX, p->cameraY);
|
||||
shader.setTileMapOffset(p->tilemapOffsetX, p->tilemapOffsetY);
|
||||
|
||||
p->gpuBuffer.clear();
|
||||
p->gpuBuffer.insert(p->gpuBuffer.end(), p->staticLightSources.begin(), p->staticLightSources.end());
|
||||
p->gpuBuffer.insert(p->gpuBuffer.end(), p->dynamicLightSources.begin(), p->dynamicLightSources.end());
|
||||
shader.setLightSources(p->gpuBuffer);
|
||||
shader.setAmbient(p->ambient);
|
||||
|
||||
boost::chrono::high_resolution_clock::time_point currentTime = boost::chrono::high_resolution_clock::now();
|
||||
boost::chrono::duration<float> elapsed = currentTime - startTime;
|
||||
shader.setTime(elapsed.count());
|
||||
|
||||
glState.blendMode.pushSet(BlendMultiply);
|
||||
|
||||
p->bitmap->bindTex(shader);
|
||||
|
||||
p->quad.draw();
|
||||
|
||||
glState.blendMode.pop();
|
||||
}
|
||||
|
||||
void LightMap::onGeometryChange(const Scene::Geometry &geo){
|
||||
/* Offset at which the sprite will be drawn
|
||||
* relative to screen origin */
|
||||
p->trans.setGlobalOffset(geo.offset());
|
||||
|
||||
p->sceneRect.setSize(geo.rect.size());
|
||||
p->sceneOrig = geo.orig;
|
||||
}
|
||||
|
||||
void LightMap::releaseResources(){
|
||||
unlink();
|
||||
|
||||
delete p;
|
||||
}
|
||||
50
src/lightmap.h
Normal file
50
src/lightmap.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef SPRITE_H
|
||||
#define SPRITE_H
|
||||
|
||||
#include "scene.h"
|
||||
#include "flashable.h"
|
||||
#include "disposable.h"
|
||||
#include "viewport.h"
|
||||
#include "util.h"
|
||||
#include "shader.h"
|
||||
|
||||
#include <boost/chrono.hpp>
|
||||
|
||||
class Bitmap;
|
||||
|
||||
struct LightMapPrivate;
|
||||
|
||||
class LightMap : public ViewportElement, public Flashable, public Disposable{
|
||||
public:
|
||||
LightMap(Viewport *viewport = 0);
|
||||
~LightMap();
|
||||
|
||||
void update();
|
||||
|
||||
DECL_ATTR( Bitmap, Bitmap* )
|
||||
DECL_ATTR( WallMap, Bitmap* )
|
||||
DECL_ATTR( CameraX, int )
|
||||
DECL_ATTR( CameraY, int )
|
||||
DECL_ATTR( TilemapOffsetX, int )
|
||||
DECL_ATTR( TilemapOffsetY, int )
|
||||
DECL_ATTR( Ambient, float )
|
||||
|
||||
void clearStaticLightSources();
|
||||
void clearDynamicLightSources();
|
||||
void addStaticLightSource(LightSource source);
|
||||
void addDynamicLightSource(LightSource source);
|
||||
void initDynAttribs();
|
||||
|
||||
private:
|
||||
LightMapPrivate *p;
|
||||
|
||||
void draw();
|
||||
void onGeometryChange(const Scene::Geometry &);
|
||||
|
||||
void releaseResources();
|
||||
const char *klassName() const { return "lightmap"; }
|
||||
|
||||
ABOUT_TO_ACCESS_DISP
|
||||
};
|
||||
|
||||
#endif // SPRITE_H
|
||||
|
|
@ -56,6 +56,7 @@
|
|||
#include "blurH.vert.xxd"
|
||||
#include "blurV.vert.xxd"
|
||||
#include "obscured.frag.xxd"
|
||||
#include "dynamicLight.frag.xxd"
|
||||
|
||||
#include "meow.h"
|
||||
#include "sunshine.h"
|
||||
|
|
@ -200,7 +201,7 @@ void Shader::setVec4Uniform(GLint location, const Vec4 &vec) {
|
|||
|
||||
void Shader::setTexUniform(GLint location, unsigned unitIndex, TEX::ID texture) {
|
||||
GLenum texUnit = GL_TEXTURE0 + unitIndex;
|
||||
|
||||
|
||||
gl.ActiveTexture(texUnit);
|
||||
gl.BindTexture(GL_TEXTURE_2D, texture.gl);
|
||||
gl.Uniform1i(location, unitIndex);
|
||||
|
|
@ -275,6 +276,65 @@ void SimpleShader::setTexOffsetX(int value){
|
|||
}
|
||||
|
||||
|
||||
DynamicLightShader::DynamicLightShader(){
|
||||
INIT_SHADER(simple, dynamicLight, DynamicLightShader);
|
||||
|
||||
ShaderBase::init();
|
||||
|
||||
GET_U(wallMapTexture);
|
||||
GET_U(wallMapResolution);
|
||||
GET_U(cameraPosition);
|
||||
GET_U(tileMapOffset);
|
||||
GET_U(lightSourcesCount);
|
||||
GET_U(ambientLight);
|
||||
|
||||
u_lightSources = gl.GetUniformLocation(program, "lightSources[0]");
|
||||
u_lightSourcesColors = gl.GetUniformLocation(program, "lightSourcesColors[0]");
|
||||
}
|
||||
|
||||
void DynamicLightShader::setWallMapTexture(TEX::ID texture){
|
||||
setTexUniform(u_wallMapTexture, 1, texture);
|
||||
}
|
||||
|
||||
void DynamicLightShader::setWallMapResolution(int x, int y){
|
||||
gl.Uniform2f(u_wallMapResolution, x, y);
|
||||
}
|
||||
|
||||
void DynamicLightShader::setCameraPosition(int x, int y){
|
||||
gl.Uniform2f(u_cameraPosition, x, y);
|
||||
}
|
||||
|
||||
void DynamicLightShader::setTileMapOffset(int x, int y){
|
||||
gl.Uniform2f(u_tileMapOffset, x, y);
|
||||
}
|
||||
|
||||
void DynamicLightShader::setLightSources(std::vector<LightSource> sources){
|
||||
gl.Uniform1i(u_lightSourcesCount, sources.size());
|
||||
for(int i = 0; i < sources.size(); i++)
|
||||
{
|
||||
if (!sources[i].hasEffect())
|
||||
continue;
|
||||
|
||||
gl.Uniform4f(u_lightSources + i,
|
||||
sources[i].x,
|
||||
sources[i].y,
|
||||
sources[i].power,
|
||||
sources[i].radius
|
||||
);
|
||||
gl.Uniform4f(u_lightSourcesColors + i,
|
||||
sources[i].color.red / 255.0,
|
||||
sources[i].color.green / 255.0,
|
||||
sources[i].color.blue / 255.0,
|
||||
sources[i].color.alpha / 255.0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicLightShader::setAmbient(float power){
|
||||
gl.Uniform1f(u_ambientLight, power);
|
||||
}
|
||||
|
||||
|
||||
SimpleColorShader::SimpleColorShader(){
|
||||
INIT_SHADER(simpleColor, simpleColor, SimpleColorShader);
|
||||
|
||||
|
|
|
|||
19
src/shader.h
19
src/shader.h
|
|
@ -103,6 +103,22 @@ private:
|
|||
GLint u_texOffsetX;
|
||||
};
|
||||
|
||||
|
||||
class DynamicLightShader : public ShaderBase{
|
||||
public:
|
||||
DynamicLightShader();
|
||||
|
||||
void setWallMapTexture(TEX::ID texture);
|
||||
void setWallMapResolution(int x, int y);
|
||||
void setCameraPosition(int x, int y);
|
||||
void setTileMapOffset(int x, int y);
|
||||
void setLightSources(std::vector<LightSource> sources);
|
||||
void setAmbient(float power);
|
||||
|
||||
private:
|
||||
GLint u_wallMapTexture, u_wallMapResolution, u_cameraPosition, u_tileMapOffset, u_lightSources, u_lightSourcesCount, u_lightSourcesColors, u_ambientLight;
|
||||
};
|
||||
|
||||
class SimpleColorShader : public ShaderBase{
|
||||
public:
|
||||
SimpleColorShader();
|
||||
|
|
@ -353,7 +369,8 @@ private:
|
|||
X(blt, BltShader, Blt) \
|
||||
X(simpleMatrix, SimpleMatrixShader, SimpleMatrix) \
|
||||
X(blur, BlurShader, Blur) \
|
||||
X(obscured, ObscuredShader, Obscured)
|
||||
X(obscured, ObscuredShader, Obscured) \
|
||||
X(dynamicLight, DynamicLightShader, DynamicLight)
|
||||
|
||||
struct ShaderSet{
|
||||
#define DECLARE_SHADER(name, type, rb) type name;
|
||||
|
|
|
|||
|
|
@ -442,6 +442,9 @@ void Sprite::setBlendType(int type){
|
|||
case BlendSubstraction :
|
||||
p->blendType = BlendSubstraction;
|
||||
return;
|
||||
case BlendMultiply :
|
||||
p->blendType = BlendMultiply;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,12 +63,6 @@ static const int atAreaW = autotileW * 4;
|
|||
static const int atAreaH = autotileH * autotileCount;
|
||||
|
||||
static const int tsLaneW = tilesetW / 2;
|
||||
/* Map viewport size */
|
||||
//TODO: разные значения под разные разрешения экрана для оптимизации
|
||||
static const int viewpW = 42;
|
||||
static const int viewpH = 26;
|
||||
|
||||
static const size_t zlayersMax = viewpH + 5;
|
||||
|
||||
/* Vocabulary:
|
||||
*
|
||||
|
|
@ -255,6 +249,9 @@ struct TilemapPrivate {
|
|||
std::vector<uint8_t> animatedATs;
|
||||
} atlas;
|
||||
|
||||
int viewpW, viewpH;
|
||||
size_t zlayersMax;
|
||||
|
||||
/* Map viewport position */
|
||||
Vec2i viewpPos;
|
||||
|
||||
|
|
@ -262,11 +259,11 @@ struct TilemapPrivate {
|
|||
SVVector groundVert;
|
||||
|
||||
/* ZLayer vertices */
|
||||
SVVector zlayerVert[zlayersMax];
|
||||
std::vector<SVVector> zlayerVert;
|
||||
|
||||
/* Base quad indices of each zlayer
|
||||
* in the shared buffer */
|
||||
size_t zlayerBases[zlayersMax+1];
|
||||
std::vector<size_t> zlayerBases;
|
||||
|
||||
/* Shared buffers for all tiles */
|
||||
struct{
|
||||
|
|
@ -285,7 +282,7 @@ struct TilemapPrivate {
|
|||
/* Scene elements */
|
||||
struct{
|
||||
GroundLayer *ground;
|
||||
ZLayer* zlayers[zlayersMax];
|
||||
std::vector<ZLayer*> zlayers;
|
||||
/* Used layers out of 'zlayers' (rest is hidden) */
|
||||
size_t activeLayers;
|
||||
Scene::Geometry sceneGeo;
|
||||
|
|
@ -330,8 +327,14 @@ struct TilemapPrivate {
|
|||
buffersDirty(false),
|
||||
mapViewportDirty(false),
|
||||
zOrderDirty(false),
|
||||
tilemapReady(false)
|
||||
tilemapReady(false),
|
||||
viewpW(shState->graphics().width() / 32 + 1),
|
||||
viewpH(shState->graphics().height() / 32 + 2),
|
||||
zlayersMax(viewpH + 5)
|
||||
{
|
||||
zlayerVert.resize(zlayersMax);
|
||||
zlayerBases.resize(zlayersMax + 1);
|
||||
|
||||
SDL_memset(autotiles, 0, sizeof(autotiles));
|
||||
|
||||
atlas.animatedATs.reserve(autotileCount);
|
||||
|
|
@ -351,6 +354,7 @@ struct TilemapPrivate {
|
|||
GLMeta::vaoInit(tiles.vao);
|
||||
|
||||
elem.ground = new GroundLayer(this, viewport);
|
||||
elem.zlayers.resize(zlayersMax);
|
||||
|
||||
for (size_t i = 0; i < zlayersMax; ++i)
|
||||
elem.zlayers[i] = new ZLayer(this, viewport);
|
||||
|
|
@ -363,8 +367,8 @@ struct TilemapPrivate {
|
|||
~TilemapPrivate(){
|
||||
/* Destroy elements */
|
||||
delete elem.ground;
|
||||
for (size_t i = 0; i < zlayersMax; ++i)
|
||||
delete elem.zlayers[i];
|
||||
for (ZLayer* ptr : elem.zlayers)
|
||||
delete ptr;
|
||||
|
||||
shState->releaseAtlasTex(atlas.gl);
|
||||
|
||||
|
|
@ -820,7 +824,7 @@ struct TilemapPrivate {
|
|||
* are muted via the 'batchedFlag'. For simplicity,
|
||||
* single sized batches are possible. */
|
||||
void prepareZLayerBatches(){
|
||||
ZLayer *const *zlayers = elem.zlayers;
|
||||
ZLayer *const *zlayers = elem.zlayers.data();
|
||||
|
||||
for (size_t i = 0; i < elem.activeLayers; ++i){
|
||||
ZLayer *batchHead = zlayers[i];
|
||||
|
|
|
|||
Loading…
Reference in a new issue