[RGD] DirectX implementation of RGSS3

Discussion in 'Useful Development Tools' started by invwindy, May 13, 2018.

  1. ZirconStorms

    ZirconStorms VX & VX Ace Scripts Veteran

    Messages:
    311
    Likes Received:
    100
    First Language:
    English
    Primarily Uses:
    RMVXA
    Any plans to implement any sort of video player with this in the future? This is an awesome project.
    There seems to be some errors with smoothly exiting fullscreen mode. After a minute or so, it finally managed to exit out of fullscreen, but the outside window borders changed. ( Please ignore the 0 and 3 FPS counters, I just exited the game windows to capture the images. Played with Windows 8.1 + NVIDIA GeForce GTX 745.)

    upload_2018-9-15_12-49-19.png

    VS how it looks if I never enter fullscreen mode:

    upload_2018-9-15_12-49-47.png
     
  2. Sixth

    Sixth Veteran Veteran

    Messages:
    2,122
    Likes Received:
    792
    First Language:
    Hungarian
    Primarily Uses:
    RMVXA
    There's something seriously wrong with your PC if it takes over 1 minute to exit fullscreen mode. o_O
    Or maybe it's Windows 8 or some other programs in the background.
    It takes maybe 2 or 3 seconds max for me on a kinda old laptop with several other programs open, but I use Windows 7, so it might be different.
    The window border change is still an issue on both Windows versions. I reported this a while back too.
     
  3. gstv87

    gstv87 Veteran Veteran

    Messages:
    1,701
    Likes Received:
    720
    First Language:
    Spanish
    Primarily Uses:
    RMVXA
    disable visual themes completely and see if that changes anything.
     
  4. Sixth

    Sixth Veteran Veteran

    Messages:
    2,122
    Likes Received:
    792
    First Language:
    Hungarian
    Primarily Uses:
    RMVXA
    After some extensive testing, I found several issues, all of them similar to some old bugs already fixed.
    1. The eql? method in Tone class has the same error the Color class had. The game crashes if it's compared with another class. Same fix can be applied here too, so that if they are different classes, the method returns false immediately.
    2. The Sprite, Plane, Viewport and Window classes got the same issue with their tone property like the color property of sprites had. Again, same fix can be applied here, so that each tone property remains unique.
    3. The Plane and Viewport classes got the same issue with their color property like the color property of sprites had. Again, same fix can be applied here, so that each color property remains unique.
    4. The Sprite class got the same issue with it's src_rect property like the color property of sprites had. Again, same fix can be applied here, so that each src_rect property remains unique.
    5. The Viewport class got the same issue with it's rect property like the color property of sprites had. Again, same fix can be applied here, so that each rect property remains unique.
    Until the next update comes, here is the fix for all of the above bugs:
    Code:
    class Tone
    
      alias fix_eql9927 eql?
      def eql?(other)
        return false unless self.class == other.class
        return fix_eql9927(other)
      end
     
    end
    
    class Sprite
     
      def tone=(val)
        self.tone.red = val.red
        self.tone.green = val.green
        self.tone.blue = val.blue
        self.tone.gray = val.gray
      end
     
      def src_rect=(val)
        self.src_rect.x = val.x
        self.src_rect.x = val.y
        self.src_rect.width = val.width
        self.src_rect.height = val.height
      end
     
    end
    
    class Plane
     
      def color=(val)
        self.color.red = val.red
        self.color.green = val.green
        self.color.blue = val.blue
        self.color.alpha = val.alpha
      end
     
      def tone=(val)
        self.tone.red = val.red
        self.tone.green = val.green
        self.tone.blue = val.blue
        self.tone.gray = val.gray
      end
       
    end
    
    class Viewport
     
      def color=(val)
        self.color.red = val.red
        self.color.green = val.green
        self.color.blue = val.blue
        self.color.alpha = val.alpha
      end
     
      def tone=(val)
        self.tone.red = val.red
        self.tone.green = val.green
        self.tone.blue = val.blue
        self.tone.gray = val.gray
      end
     
      def rect=(val)
        self.rect.x = val.x
        self.rect.y = val.y
        self.rect.width = val.width
        self.rect.height = val.height
      end
     
    end
    
    class Window
    
      def tone=(val)
        self.tone.red = val.red
        self.tone.green = val.green
        self.tone.blue = val.blue
        self.tone.gray = val.gray
      end
     
    end
    
    This snippet will restore the original behavior of these properties/methods.
     
    Last edited: Nov 20, 2018
  5. gstv87

    gstv87 Veteran Veteran

    Messages:
    1,701
    Likes Received:
    720
    First Language:
    Spanish
    Primarily Uses:
    RMVXA
    src_rect must be .set, not =(rect)
    I don't think I've ever seen it assigned in the code, it's always modified through .set()
    in fact, I was hoping to hook onto the assignment method to fix a problem with the WOR, but noticed window_selectable doesn't assign it when controlling the cursor, it .set()'s it.
    that would have meant I would have had to modify the Rect object as well, which was not an option.

    Tone? I believe it's the same thing.... although, that, I didn't test.
     
  6. Sixth

    Sixth Veteran Veteran

    Messages:
    2,122
    Likes Received:
    792
    First Language:
    Hungarian
    Primarily Uses:
    RMVXA
    It seems like you didn't test any of these properties at all.
    They are all built-in properties, and they can all be set directly with their method= writer methods.Even the help files mention them.
    Make sure to test them with and without RGD and you will see the difference.

    Windows don't have a src_rect property, which is why you couldn't do what you wanted to do in the way you wanted to do it first. The classes I mentioned all have the properties I mentioned by default.

    You won't see much of these methods used in the default code, because those barely even use these classes, they just make the objects, and leave them like that forever. But if you want to make something way more dynamic, unique and... not so default looking, you have to use them, and use them well.
     
  7. gstv87

    gstv87 Veteran Veteran

    Messages:
    1,701
    Likes Received:
    720
    First Language:
    Spanish
    Primarily Uses:
    RMVXA
    not windows, the cursor rectangle for selectables, which is a Rect.
    which is actually a link to a Sprite within the Window.

    Sprite's src_rect is a Rect, which you dont =(), you .set().
    do a broad search for "src_rect =" in the code, you won't find any, they're all src_rect.set()

    Viewport.rect=() is already implemented.
    I've used it for a quick fix and it worked just fine, you don't need to re-define it.

    Tones are the only thing I didn't research, because I just saved Tones in Tones, I didn't mess with their individual parts.
     
    Last edited: Sep 20, 2018
  8. Sixth

    Sixth Veteran Veteran

    Messages:
    2,122
    Likes Received:
    792
    First Language:
    Hungarian
    Primarily Uses:
    RMVXA
    Restricting yourself by only following the default code from the engine is a fine way of limiting your own potential in coding.
    You can do a search for .merge in the default code too, that's not used there either, yet it's still a wonderful method of the Hash class and is ready to be used for those who find it useful. I could list tons of other great methods never used in the default scripts, but I think my point is clear here. :p

    The class of a property object got nothing to do with how you can set it or what you can set it to. It's just that, a property that can be changed with the property_name=(value) method. You can even set that src_rect property to an integer number if you want to, but of course, it will break the Sprite class, because that expects a Rect object.

    You seem to mix two things here.
    The src_rect property is a property of the Sprite class, which happens to expect a Rect object as it's value. The set method is a method in the Rect class. They are completely separate things. You can use the set method on the Sprite class' src_rect property if you want, obviously, since it's a Rect object. But that doesn't mean that you can't directly set the src_rect property of the Sprite class to a new Rect object.

    You surely didn't work with these properties, because if you would have, you would know how they work.
    You may ask why didn't I just use that set method on the property itself, and the answer is simple: because I don't have to, it's easier this way, and my code is much shorter and way more dynamic this way. Here is an example:
    Code:
    module ExSetup
    
      Cmds = {
        :back => {
          :img => "item1",
          :x => 87, :y => 12, :ox => 87, :oy => 12,
          :src_rect => Rect.new(0,0,0,24),
          :tone => Tone.new(0,0,0,255), :blend_type => 1,
          :color => Color.new(255,255,255,181),
        },
        :name => {
          :txt => "Command <index>", :w => 175, :h => 24,
          :x => 87, :y => 12, :ox => 87, :oy => 12,
          :src_rect => Rect.new(0,0,0,24),
          :tone => Tone.new(0,0,0,255),
        },
      }
     
    end
    
    class CmdVis
     
      def initialize(data)
        @data = data
        @index = 0
        init_commands
      end
     
      def init_commands
        @cmds = {}
        10.times do |i| # Just some random way of making more commands
          @data.each do |sym,props|
            ikey = [i,sym]
            @cmds[ikey] = Sprite.new
            apply_props(@cmds[ikey],props,i)
            @cmds[ikey].y += i * 32
          end
        end
      end
     
      def apply_props(sp,props,i)
        props.each do |prop,val|
          case prop
          when :w, :h
            # Non-existent properties used in other parts of the code can be skipped
            # easily here.
            next
          when :img
            # Image loading, simplified.
            sp.bitmap = Cache.picture(val)
          when :txt
            # Text drawing, simplified.
            sp.bitmap = Bitmap.new(props[:w],props[:h])
            sp.bitmap.draw_text(0,0,props[:w],props[:h],process_txt(val.clone,i),1)
          else
            # And this part lets the user of the script setup any valid properties
            # while making the code way shorter and easy to read.
            sp.send(prop.to_s+"=",val)
          end
        end
      end
     
      def process_txt(tx,i)
        tx.gsub!("<index>") { i }
        return tx
      end
     
      def update
        if Input.trigger?(:UP)
          @index -= 1
          @index = @cmds.size - 1 if @index < 0
        elsif Input.trigger?(:DOWN)
          @index += 1
          @index = 0 if @index > @cmds.size - 1
        end
        if Input.trigger?(:LEFT)
          trgs = @cmds.select {|ky,sp| ky[0] == @index }
          trgs.each {|ky,sp| sp.src_rect.width = 0 }
        elsif Input.trigger?(:RIGHT)
          trgs = @cmds.select {|ky,sp| ky[0] == @index }
          trgs.each {|ky,sp| sp.src_rect.width = 175 }
        end
        if Input.trigger?(:C)
          dispose
        end
      end
     
      def disposed?
        return @disposed
      end
     
      def dispose
        @cmds.each_value {|sp| sp.bitmap.dispose; sp.dispose}
        @disposed = true
      end
     
    end
    
    test = CmdVis.new(ExSetup::Cmds)
    
    loop do
      Input.update
      Graphics.update
      test.update
      break if test.disposed?
    end
    Barely 100 lines (most of it is not even related to the command images made with it), yet it can make a full command list with any amount of images and with any type of image property settings.
    It's just a quick example made in a few minutes. There are many more situations where setting these properties directly is much easier for the coder and for the code too.
    Try to test this snippet with and without the RGD, and check the difference yourself, now for real.
    Just change that image setting to an image from the "Graphics/Pictures/" folder, and it's ready for testing.
     
  9. gstv87

    gstv87 Veteran Veteran

    Messages:
    1,701
    Likes Received:
    720
    First Language:
    Spanish
    Primarily Uses:
    RMVXA
    no, it's a way of making sure whatever program you make runs with what the engine can handle.

    yes, but since the Sprite object is set to expect a modification to it's structure through the src_rect property, you send it through the src_rect property!
    it being a Rect object should not have to be of question outside the Sprite object itself. You can pass it a Rect object and Sprite itself can then break it down into individual variables, internally.
    what do you know if the src_rect property itself doesn't have additional code in it *after* setting up the relevant properties *as you do* by using the rect=() method?
    I had to answer that question by working with Sprites within Windows, building the Window Replacement, and having the sprites not update correctly.
    you can't just set a new method to do what you expect it to do when you can't assert what the original method itself does, which you can't know, when you don't have the original code.
    the only thing you have is the engine responding to a bunch of code..... if what you send to it doesn't work, you can use the response to try and figure out what it might do, but you can't assume since the returned value is an object X that the internal value is also the same object.
    if you have MV, find the Window object and check how it returns it's opacity.
     
  10. Sixth

    Sixth Veteran Veteran

    Messages:
    2,122
    Likes Received:
    792
    First Language:
    Hungarian
    Primarily Uses:
    RMVXA
    I just reported the bugs I found, and provided the fixes for them.
    You don't have to use my fixes if you don't want to. You probably won't even need these fixes seeing as you don't even know about or use any of these methods.

    I don't want to derail this topic to something sparkly. Our opinions about coding is clearly day and night, so I will just agree to disagree.
    My inbox is open in case you want to continue this conversation.
     
  11. TheoAllen

    TheoAllen Self-proclaimed jack of all trades Veteran

    Messages:
    4,211
    Likes Received:
    4,661
    Location:
    Riftverse
    First Language:
    Indonesian
    Primarily Uses:
    RMVXA
    I just noticed that F12 is also disabled while it's not listed in the documentation of difference between RGD and RGSS3.
    I know some people just hate F12 reset function and want to disable it all together. But it's a great shortcut for testing to reset everything without closing the window and playtest it again. Any plan or a way to restore it back?
     
  12. Valentine90

    Valentine90 Veteran Veteran

    Messages:
    36
    Likes Received:
    12
    Location:
    Brazil
    First Language:
    Português
    Primarily Uses:
    RMVXA
    If you are restoring the F12 command, please make optional. This function generates many problems and is not convincing in all projects.
     
  13. BCj

    BCj Veteran Veteran

    Messages:
    1,395
    Likes Received:
    655
    Location:
    NL
    First Language:
    Dutch
    Primarily Uses:
    N/A
    Curious as to when the next update (and hopefully the lightning script fix) is released :)
     
  14. gstv87

    gstv87 Veteran Veteran

    Messages:
    1,701
    Likes Received:
    720
    First Language:
    Spanish
    Primarily Uses:
    RMVXA
    just asking something real quick:
    [​IMG]
    did you manage to fix that table tile issue in 1.2.1? or is it scheduled for the next version?
    working on autotiles ATM, I can see the effect in the editor, but not in the game.
     
  15. invwindy

    invwindy Ice Fairy Veteran

    Messages:
    64
    Likes Received:
    58
    First Language:
    Chinese
    Primarily Uses:
    RMVXA
    Thank you everyone. I'm quite busy these days. All the problems reported are going to be fixed in the next update.
    I'm also thinking about reimplementing audio part of RGSS3, adding more operations and binaural volume control. I'm using XAudio2 but I don't know if XAudio2 runtime is installed on most computer.
     
    BCj likes this.
  16. Engr. Adiktuzmiko

    Engr. Adiktuzmiko Chemical Engineer, Game Developer, Using BlinkBoy' Veteran

    Messages:
    14,456
    Likes Received:
    2,844
    Location:
    Philippines
    First Language:
    Tagalog
    My brother is playtesting my game and somehow if it's using the RGD exe, after about 15 minutes or so the font seems to get "broken". Most texts done in selectable windows gets drawn around 8 pixels lower, and most texts become something like "a a a a a".. If the game is closed an reopened, it works fine again until about 15 minutes and the issue returns. I'm using the VL Gothic font.
     
  17. AceOfAces_Mod

    AceOfAces_Mod Engineering to infinity! Veteran

    Messages:
    1,694
    Likes Received:
    1,143
    First Language:
    Greek
    Primarily Uses:
    RMVXA
    @invwindy , XAudio2 is pre-installed, but it depends on the version of Windows and the version of XAudio2. Version 2.7 needs the June 2010 updates for DirectX (which isn't included by default). 2.8 and newer are included on Windows by default since Windows 8.
     
  18. Sixth

    Sixth Veteran Veteran

    Messages:
    2,122
    Likes Received:
    792
    First Language:
    Hungarian
    Primarily Uses:
    RMVXA
    No idea if anyone had the "luck" of encountering the issue I'm about to describe, but maybe it will help some people...

    After setting up the GPU preference on my laptop to use my GeForce instead of my CPU for the game, I noticed that sometimes the FPS will switch to 30 and it will stay that way until the game is restarted (setting Graphics.frame_rate to anything higher than 30 manually won't have any effect either). This usually happens if I load lots of bitmaps at once, but oddly enough, sometimes it happens as soon as I enter the map scene (where no custom things are running at all, only default code there).

    So, I went to check my GPU settings for VX Ace (for the Game.exe), and I found an option called "Power Management Mode". It was set to "Use global Setting (Optimal)" by default (because that's my global setting for that option, obviously). Changing that to "Prefer maximum performance" fixed the FPS drop issue.
    This is how the option is named in the NVIDIA Control Panel. It may have a different name in ATI Control Panel (or however it's called for those cards these days).

    This bothered me for a long time, so I thought, it may be worth to share my debugging results.
    The solution I found for this issue indicates that it's not a problem of RGD, but a "problem" of the user's GPU setting / hardware limitation.
    I have yet to trigger this issue on my brother's laptop (which is newer and much stronger than mine) regardless of the GPU settings I use on it, so it's safe to say that it depends on the hardware as well (like it should, after all, it's a performance related thing).

    Now I'm curious about that text bug Adik mentioned. I didn't manage to trigger it yet, but I will keep trying. :D

    The audio part sounds cool, but without a custom installer which includes the required audio runtime(s), I wouldn't include it in my projects.
    It would be cool to use multiple audio channels, would make mixing and transitioning audio effects much better for sure.
    Just keep it as an optional feature for people who don't like to force their players to use 3rd party software.

    And while we are at the optional part...
    I see some people prefer the current full screen render mode in RGD over the default one from the engine, mainly because it keeps the sharpness of the images.
    I only assume that the mode is set to "nearest neighbor", or to a similar mode.
    I like the sharper images too, but some of the texts are hard to read on images this way, even text drawn with the default draw_text method looks bad sometimes with certain font types (especially with small font sizes).
    I would screenshot some examples, but... The printscreen key doesn't seem to capture anything if the game is on fullscreen mode, just a blank black screen. Can I request a fix for this, pretty please? No hurries, just reporting it, so you know about it.
    Back to the fullscreen rendering mode... Can we, as the developers, change the rendering mode somehow? Or is it hard-coded now? I want to give the player the option of choosing between these modes in case the default one doesn't fancy their liking. It's not a mandatory thing by any means, I just want to avoid these text issues somehow. Since the ratio depends on the resolution of the player's monitor and the resolution of the game, it may or may not break some texts, so this option may or may not be necessary for people, which is why I want to let the players choose the mode themselves.

    Phew, this got longer than expected. >.>
     
    BCj likes this.
  19. Sixth

    Sixth Veteran Veteran

    Messages:
    2,122
    Likes Received:
    792
    First Language:
    Hungarian
    Primarily Uses:
    RMVXA
    Not sure if this counts for double post or not, but it's something important to those folks using that lighting system script @invwindy made, so...

    After testing the scripts in the demo project, I found lots and lots of memory leaks and critical errors with sprite disposal, and the latter will make the game crash randomly, but still quickly if using particle effects (those can rack up so quick, even the debugger can't keep up with them).

    Here are the fixes for all of these major issues:
    Code:
    =begin
    
    This little script fixes the memory leaks and critical sprite disposal errors 
    found in invwindy's RGD Lighting system.
    
    Put it right below the 'RGD Lighting - Main' script!
    
    Made by: Sixth
    
    =end
    
    module Cirno::Light
    
      class LightLayer
       
        def create_shadow
          @shadow_sprite = Sprite.new(@viewport_illumination)
          @shadow_sprite.z = 0
          # Removed - by Sixth!
          #@shadow_walltop_sprite = Sprite.new(@viewport_shadow)
          @shadow_walltop_sprite = Occlusion.create_walltop_sprite(
            @viewport_shadow, 100, "GeoSprite")
        end
    
        alias disp_the_rest5521 dispose_shadow
        def dispose_shadow
          disp_the_rest5521
          # Disposed the rest of them - by Sixth!
          @shadow_walltop_sprite.bitmap.dispose
          @shadow_walltop_sprite.dispose
          @viewport_shadow.dispose
        end
    
      end
    
    end
    
    class Spriteset_Map
    
      alias kill_particls9971 dispose_light
      def dispose_light
        # Killed old particle spawners - by Sixth!
        @particles = {}
        kill_particls9971
      end
    
      def dispose
        # Dispose order changed - by Sixth!
        dispose_light
        cirno_20180808_dispose
      end
    
    end
    
    I marked what exactly I changed/added.

    It's a nice lighting system, btw. Too bad that all particle effects disappear on scene/map change.
    Although it should be possible to save the data of the on-screen particles and re-load them after the scene/map change. Maybe I will do an addon for it sometimes.

    The only reason I debugged this script is because Khas' Ultra Lighting system is not compatible with RGD, and because of that, I kinda need an alternative. >.>
     
    BCj likes this.
  20. invwindy

    invwindy Ice Fairy Veteran

    Messages:
    64
    Likes Received:
    58
    First Language:
    Chinese
    Primarily Uses:
    RMVXA
    Thank you @Sixth ! I'm going to look at your reports in detail after finishing my current work, which may take about two weeks.
    And thanks for your explanation @AceOfAces_Mod !
     

Share This Page