ScummVM logo ScummVM website - Forums - BuildBot - Doxygen
Contact us - Buy Supported Games: GOG.comDotEmu 
curved edge

PlanetPlanet

Welcome to the ScummVM planet - This aggregates the personal blogs of developers, teams members and active participants from all around the ScummVM community.
If you wish to subscribe to updates to the planet or individual blogs please use the links on the right hand side.
To add your blog to the planet contact DJWillis.

August 19, 2014

Joseph Jezak (JoseJX) - GSoC

The Raft Spin

After the rotation fixes, one weird issue remained with Guybrush, when getting on the raft in the set mot. When Guybrush got on the raft, he would strangely rotate in a circular motion once on the raft.

To debug the problem, I commented out the lines in the set file mot.lua regarding guybrush getting on the raft and found that it was a call to setrot which caused the issue to occur. In this call, setrot was called with TRUE as the fourth parameter, causing Guybrush to rotate over time instead of snapping to the rotation. Due to some difficulties with getting the rotation before Guybrush turned out of the retail version, I used a textObject in the lua script before setrot was called to display the values. Here's the retail version and ResidualVM:
Guybrush's rotation before getting on the raft in the Retail Version
Guybrush's rotation before getting on the raft in ResidualVM
As can be seen, the yaw parameter is inverted! So, is this the issue that's causing the weird rotation? I tried setting Guybrush's rotation before calling setrot(0, 0, 0, TRUE) with guybrush:setrot(180, 69.8599, 180) and found that the weird rotation still occurred. So, it seems there are actually two problems here:
  1. When rotating, Guybrush is sometimes rotated in axes that he shouldn't be when setrot is called without snapping to the new angles
  2. Guybrush's rotation is incorrect, with the yaw axis returning a negative value when it should be positive
To inspect the first problem, I tried setting Guybrush's rotation to 0 in each of the axes independently and inspecting the result and found that no axis was directly responsible for this rotation. I then tried setting them all to 0 with a snap and found that this looked correct (which was expected, obviously). The next experiment was to set each of the angles to a part of the rotation. I tried (0, 69.8599, 0) first and found that the result looked right, indicating that the pitch and roll axes might be causing the problem. I then tried (45, 69.8599, 45) and found that it also looked correct! However, at (90, 69.8599, 90), the issue re-appeared. In fact, any value below 90 seemed to work okay, while values greater than 90 caused problems. Out of curiosity, I then tried (-45, 69.8599, -45) and found that it also worked fine! In fact, values between -90 and 90 (non-inclusive) seemed to produce the correct result, while values outside that range produced incorrect behavior.

This pointed to a problem with the conversions between Euler angles and other rotation forms in that angles between (-90, 90) were calculated correctly, but larger angles were not. First, I checked the functions that I wrote by implementing a simple perl program to compute the rotation matrices from Euler Angles and back again. This program can be found here and produces results demonstrating the correct equations for setting a rotation matrix from Euler Angles and retrieving the Euler Angles from the matrix:
Output from computing the Euler -> Matrix conversion for ZYX
Fortunately (or unfortunately for finding the bug!) the results matched and there wasn't an obvious problem, aside from the absence of checking for singularities or gimbal lock checking. However, I was having trouble keeping the X's for the axis and the X's for the Euler Angles straight, so as a part of this work, I reworked the Euler Angle nomenclature to make the naming more consistent with the usage.

With the nomenclature straightened out, I then added a fix for singularities that arise from when it's impossible to determine the correct result. For an Euler Order of ZYX, we can see that when the Y Euler Angle is pi/2 (or 90 degrees), it will be impossible to differentiate the other two angles. We can see this by inspecting the figure above, where we can see that if the result of Cy is 0, then the components that are used by the arctan cannot be used to determine the result.  Cy is 0 when the cosine of the Y axis angle is pi/2 or -pi/2. This state results in a condition called gimbal lock. To work around this issue, we can check to see if the conversion will produce gimbal lock and if so, chose a single rotation.

So, does correcting for gimbal lock fix any of our problems? We can be fairly certain that it won't just by inspection. In the scenario above, Guybrush's coordinates would not cause a singularity because the second angle (yaw) is not +/- 90 degrees. Still, it was a necessary fix!

So, what is really going wrong here? Let's try some more experimentation! First, let's rotate Guybrush from (0,0,0) to (180, 0, 0) and (0,0,0) to (0, 0, 180):
Pitch 180 Degrees - (0,0,0) to (180, 0, 0)
Roll 180 Degrees - (0,0,0) to (0, 0, 180)

Rotation of (0,0,0) to (180, 0, 180)
We can see that the sum of these rotations is going to result in Guybrush facing 180 degrees opposite his position on the yaw axis from the (0,0,0) rotation. So, we can see that a rotation from (180, 0, 180) to (0, 0, 0) should only produce rotation in the yaw axis instead of rotating through the pitch and roll axes as well.

What causes this extra rotation? In ResidualVM, the turn methods of the Actor use Euler Angles to compute the rotation by making the angles equal. If instead, a Quaternion is used for rotation, this problem should be resolved. Now that the problem has been identified, in the next post, I'll address the issue.

by Joe Jezak (noreply@blogger.com) at August 19, 2014 12:09 PM

August 18, 2014

Joseph Jezak (JoseJX) - GSoC

What's up with Timmy?

Continued from the previous entry

In the previous entry, we started debugging the issues with the lava puzzle and found a problem with Guybrush colliding with the logs. We also found that a similar problem was occurring with the monkey Timmy, on the beach at Monkey Island. In this post, we'll try to figure out why Timmy isn't colliding with Guybrush and just running right through him instead.

Timmy on the Beach, Running Wild!
To begin with, I examined the script that controlled Timmy's running behavior. When an actor has a monkey that's running around the actor's position, a variable named monkey_range is set, which describes the maximum distance that the monkey can run from the actor in each direction. A random value within this range is chosen for the monkey to go to. The monkey runs to this location using the runto method, which is implemented by the Lua command WalkActorTo, which ultimately runs the Actor::walkTo method in ResidualVM. Within this method, the actor checks for collisions while plotting the path.

So, why isn't Timmy colliding with Guybrush? If we comment the check to print out when actors are checked for collision, we find that we can make Timmy collide with Guybrush if Guybrush walks into him, but not if Timmy runs into Guybrush when Guybrush isn't moving. If we inspect the logic that makes Timmy move, we find that there's a method in the Actor class called updateWalk which updates the character's position over the duration of the walk. If we add some code here to force a collision check when the actor is moving, Timmy stops as expected when he runs into Guybrush.

I suspect that this fixes the lava puzzle collisions too, but currently the logs in the puzzle aren't showing. I'll tackle this in the next post! This work is submitted as PR #1050.

by Joe Jezak (noreply@blogger.com) at August 18, 2014 11:20 PM

TinyGL and the Font Segfault

With the integrations of my text patches, the text rendering is much closer to the original version. Unfortunately, it was found that they also caused memory corruption, resulting in segfaults when using the TinyGL rendering path.

First, I wasn't sure exactly what was causing the segfaults, just that they were happening at seemingly random intervals and that the backtrace usually involved a text function such as drawing or freeing a text object. I put the game into gdb and found that I couldn't reliably trigger the bug to investigate the problem. I then tried running ResidualVM in valgrind and found that when creating the text object with the function createTextObject in the TinyGL rendering path, when creating the text bitmap, there was a buffer overrun. To be sure, I added an assertion to this path that asserted when the bitmap offset was larger than the bitmap storage. This confirmed the issue!

So, what changed to cause the bitmap size to be smaller than expected? If we look at the code, it appears that the TinyGL engine is allocating the text object bitmap using the kerned height and width. As it turns out, this isn't actually enough space to hold the completed text because there's an additional piece of information, the column offset. When a letter is printed without using the whole kerned space (as in the character "1"), there's an offset added to the starting column to account for this, letting the game use less storage for the character. When I accounted for this extra width, along with adding a new function to take the y offset into consideration as well, the segfault was fixed and text was rendered properly in TinyGL again! This was submitted in PR #1024.

by Joe Jezak (noreply@blogger.com) at August 18, 2014 11:20 PM

August 17, 2014

Matthew Hoops (Clone2727)

Revisiting Cinepak

While working on an as-of-yet-unnamed engine last year, I realized I needed to dither some videos. My only hope was that it wouldn't be as painful as DrMcCoy had it several years ago (and I'm pretty sure the "beauty" part was sarcastic). Looking at how the game dithers the graphics, I figured out that it relied on Video for Windows to handle dithering. VFW promptly handles it by making the codec handle it.

For this game, that codec was Cinepak. The Cinepak decoder has been in ScummVM since 2009 (I wrote it in late 2007 or so, so it's really even older). I refused to use some other dithering algorithm that would have been different and given different results. If I was going to implement this, I was going to do it to match the original 100%. That meant it was time to figure out what it does.

Basically, the algorithm is based on pre-dithered tables that are for a given hardcoded palette. For custom palettes, it finds the nearest (using a simple distance equation) color in it and maps from the Cinepak palette index to the custom one. It then uses the pre-dithered tables to generate 4x4 blocks based on the contents of the codebook which is then mapped to the custom palette.

I pushed the code for the curious.

QuickTime also does something similar (but with a different dithering algorithm in Cinepak, of course), which I'll be working on for Myst.

Here's the result, using one of the Cinepak samples from the MPlayer samples archive (in this case, the Lara Croft one):

Normal decode to 24bpp
Dither to 8bpp

The result looks pretty decent. I was mostly glad it wasn't a ridiculous amount of extra code.

by clone2727 (noreply@blogger.com) at August 17, 2014 11:14 PM

Joni Vähämäki (Akz) - GSoC

EMI is completable!

I finally got around to do a proper playthrough of EMI in ResidualVM with all the fixes and improvements made during GSoC. I'm happy to say the game can now be played from start to finish with only some minor issues :)


The biggest issue that remains right now is a bug with the lava boat puzzle on Monkey island. The boats on the lava field are not visible, which makes the puzzle difficult to complete. JoseJX is working on this issue though, so hopefully it will be resolved soon.

Other than that, there are a few graphical issues. Animations occasionally still seem to snap to the wrong frame. This happens for example when jumping out of the bank window on Lucre island, and when Guybrush gets a grog at the Micro-Groggery on Jambalaya island. Also, the text in the end credits flickers and the text color doesn't match the original.

Pathfinding is not perfect yet. Actors tend to zig-zag around before reaching their destination, which looks silly sometimes.

On the audio side, footstep sounds are sometimes wrong. For example, when walking on the Jambalaya island beach, it sounds like Guybrush is walking on wood. Also, voiceovers sometimes tend to get cut short, which is a bit annoying.

These issues will have to be resolved after GSoC though. I'm pleased that all of the issues I spotted are fairly minor, and the game is very much playable in the current state. I'm confident that support for EMI could be included in the stable release of ResidualVM fairly soon.

As GSoC soon comes to a close, I want to thank my mentors and the ScummVM/ResidualVM community for your support and for providing me this great opportunity to bring another classic adventure back to life. This has been a fun summer!



by Akz (noreply@blogger.com) at August 17, 2014 07:54 PM

August 16, 2014

Matthew Hoops (Clone2727)

Hidden in Plain Sight

With the DVD/GOG version of Pegasus Prime, there was a slight problem before release. We had an invalid function call entering the three new chase sequences when compiled in gcc with optimizations. I was unable to figure out the exact cause at the time and I ended up writing a hack around it in final release.

Since a bad function was getting called, I had feared gcc was overwriting a return address somewhere and sending the program counter where it shouldn't be. valgrind wasn't helping and only showed the after-effects of the bad function call. It was pretty hard to pinpoint in gdb too, due to the calling function being called numerous times during execution without breaking. I had shelved the issue for some time so I could return later, perhaps with another idea of tackling it. I found my hope in the AddressSanitizer.

Armed with my shiny new PC and gcc 4.8.1, I recompiled with the address sanitizer to see what I would get. The game would now crash as soon as the sequence would start, due to the sanitizer kicking in. The information the sanitizer gave helped in really one way: I had a way to make it stop as soon as it broke from the stack buffer overflow error. Perhaps not quite the way the tool was intended to be used, but it was enough of a hint for me.

With some logging to a file, I saw that it crashed here the first time _inputHandler changed. Going with LordHoto's suggestion to check the vtable of the pointer, I noticed something funny: It was the vtable for the wrong class!

Once I saw where the _inputHandler field was populated, I quickly saw what my mistake was. Instead of relying on the compiler to upcast from the subclass to the InputHandler class, I had a manual C-style cast in there. The Neighborhood pointer (only known through forward declaration) was being cast to the InputHandler pointer. Normally this would be OK, as long as the compiler knew about the class hierarchy (in this case, with multiple inheritance and virtual functions), and then generate a static_cast. But if it didn't know that, it would have to go with a reinterpret_cast. The code was doing a reinterpret_cast and throwing away the hierarchy, and therefore causing undefined behavior. It just so happened that it called into the wrong vtable in this case.

But why did it happen only during optimization? Probably because the function was getting inlined. If the include order had Neighborhood defined in the translation unit before getting to the constructor of GameInteraction, it would have output the correct static_cast. It's likely one other place had this situation and that version ended up being the actual used function.

Definitely one of the hardest bugs I've had to track down.

by clone2727 (noreply@blogger.com) at August 16, 2014 01:09 PM

August 13, 2014

Peter Bozsó (uruk) - GSoC

Merged #2

Yes, yes, yes! :) CGE2 engine is finally merged, the fruit of this summer grew ripe! :)

This week I was busy with fixing issues regarding my merge request and other problems reported by Coverity. Also, I found the sound system of the game still pretty buggy, but after a day of work, it finally works as intended. Other than that, the engine is really complete now, we are only waiting for a decent translation, and that's all, it will be free to download from our site. :)

About Avalanche: as I said, I started to work on Avalanche engine again. This week I spent my time with the objectifying of the dropdown menu's code, and now I can say that even if it's not perfect, but it's much cleaner than before and easier to read. Now, during the remaining two days of this GSoC, I plan to implement the keyboard handling of the dropdown menu. We'll see if I'll have enough time for that...

Now only the end of the program remains, so I'd like to say to you guys as a closing a big thank you for this another great summer! I am especially thankful for the work of Arnaud, Paul, David and Thierry. I wouldn't be here without you guys!

I am still very proud to be a member of ScummVM. :)

by uruk (noreply@blogger.com) at August 13, 2014 08:08 PM

August 12, 2014

Lukasz Watka (lukaslw) - GSoC

Finally completable

Hello everyone!

Great news! The Prince and the Coward is now completable! This means that we are able to play from beginning to the end of the game without skipping any important part of it. Here we have a screenshot from ending sequence to give you a proof:

Prince completable
Game ending

First thing that I had to change was hero drawing and movement to implement second hero displaying. I made some changes in Hero class (hero shadow drawing, zooming) and also update pathfinding functions for second hero and now it's working fine:

Second hero implementation
Displaying and movement

I also implement drawing "power meter" and bind it with mouse and keyboard buttons, so now last mini-game - "Escape from jail" is working correctly:

"Escape from jail"
Last mini-game

Next things that I had to code were credits loading and scrolling function for them. They are displayed after game ending animations and they look like this:

End credits
Scrolling after ending animations

I also work on graphics functions to add anti-aliasing code that exist in original version of game for sprite drawing functions. Prince is using 256 colors palette and its edge smoothing is based on 256 x 256 table of colors transition. Algorithm is checking if currently drawing pixel is located next to the edge of sprite and if it makes jagged line. If it does then this pixel is set with color from transition table calculated of original background pixel color and sprite's edge pixel color. Personally I don't see a big difference, but I think that it is visible mostly on not moving sprites, like shovel. You can compare it on screenshots below:

Anti-aliasing comparison - first location
(from left to right) Original game, ScummVM - AA on, ScummVM - AA off

Anti-aliasing comparison - shovel sprite
(from left to right) Original game, ScummVM - AA on, ScummVM - AA off

Most of work is done now, but there are still glitches that I have to fix (e.g. correct shadow drawing, fix drawing of last frames of FLC animations) and some ScummVM's Advanced Engine Features that I'd like to implement before merging of the engine.

by lukaslw (noreply@blogger.com) at August 12, 2014 07:37 PM

Joseph Jezak (JoseJX) - GSoC

Simplifying Attaching and Detaching

Continued from the previous entry.

After all of the previous work on attaching and detaching and getting it pretty close to working, I found that there were still a few issues, like the cuffs not attaching properly to Guybrush's wrists in the set wed. Additionally, after a code review by Akz, he suggested that the code could be made simpler and that instead of trying to match the internal matrices in the retail version, I should just aim to match the output. Of note was that I needed to insert a large number of transposes to make the intermediate values work.

As such, I scrapped the previous code and instead tried to fix the problem of attaching and detaching with all of the new information that I'd learned over the course of debugging this problem. This new version of the attach and detach code is much less intrusive and achieves the same result with far fewer calculations. This code was re-submitted as PR #948. So, how does the pole in the set pph look now?

The set pph after getting off the raft
Looks pretty close, the pole is in the right position, but let's compare it with the original:
Difference between retail and ResidualVM
It's a little hard to see, but there's still a different in the orientation of the pole. I'm not exactly sure where this comes from, but I suspect that it has to do with the joint rotation of Guybrush's hand. Still, the result is much better than it was before.

The next outstanding rotation issue that needed to be looked into was Issue #958. I thought that I had fixed this bug, but it appears to still be broken. The best item for displaying the issue is the itty-bitty brass screw, which is rotating on the wrong axis.
Retail
ResidualVM
As you can see, the screw starts in the wrong orientation and is upside down! Additionally, the rotation of some items in the inventory are incorrect with rotation being applied to the wrong axis. As it turns out, the orientation was incorrect because the rotation was applied backwards. Inverting the rotation Quaternion result of GetRotationQuat made this problem go away, but the resulting angle was wrong for the attached actor. This was because GetRotationQuat was being used as part of the attach and detach sequence. Iverting those usages as well found that the result now matched what we had before, except that the screw was rotated correctly.

The pole in the set pph is effected by the rotation of the hand joint in Guybrush's hand. As it turns out, the code that I had written for the attach and detach had neglected the position of the attached joint. Incorporating this rotation and translation slightly improved the position and rotation of the pole in the set mot.

At this point, I was hoping that all of the issues were resolved enough to move on, but two major issues remain:
  1. The boats in the lava puzzle were placed incorrectly, appearing (well, not actually appearing) under the lava instead of on top.
  2. When Guybrush rotates on the raft after boarding, he spins on a wrong axis.
In the next post, we'll tackle these issues!

by Joe Jezak (noreply@blogger.com) at August 12, 2014 12:51 PM

August 11, 2014

Stefano Musumeci (subr3v) - GSoC

Dirty Rectangles system performance considerations

As I've spent the last week fixing some minor bugs and documenting code, I wanted to analyse better the effects of this system on the current games.
I've done some profiling by measuring fps in two modes: analysis and release;
Analysis build is a build with less optimizations enabled and debug symbols whilst release mode is the classic o3 build with every possible optimization enabled.
The scenes used for these tests are the following:
EMI - ship scene, lucre island and act 1 beginning.
Grim demo: first scenes of the demo.

Here are some screenshots for clarity.









And here are some results.

Before dirty rectangle system (analysis / release):
Ship scene: 13.50 / 57 fps
Lucre Island: 9 / 47 fps
Act 1 Beginning: 25 / 135 fps
Grim scene 1: 50 / 160 fps
Grim scene 2: 62 / 220 fps
Grim scene 3: 57 / 243 fps
Grim scene 4: 60 / 205 fps

After dirty rectangle system (analysis / release):
Ship scene: 12 / 55 fps
Lucre Island: 9 / 45 fps
Act 1 Beginning: 24 / 133 fps
Grim scene 1: 23 / 136  fps
Grim scene 2: 62 / 500 fps
Grim scene 3: 27 / 180 fps
Grim scene 4: 42 / 250 fps

As we can see dirty rects introduces an heavy overhead, especially with analysis build; but release build is somewhat balanced: the fps is pretty much the same for crowded scenes whereas it goes up by quite a bit if the scene has only a few animated objects (like grim scene 2 or scene 4, where animated objects are small and dirty rects yield some performance advantage).

In my personal opinion dirty rects should only be employed on some specific scenarios, as its overhead generally slows down the code and it only shines in some cases.
Dirty rects is a system that is probably better off being used in 2D games where screen changes are more controllable and there is no need to perform more calculation to know which region of the screen is going to be affected.

Developing this system was quite challenging and it took a lot of time but I think that the overall task was beneficial because it gave us an insight on how this could have affected performance: I think that implementing this system on an higher level of abstraction might result in being more effective but more research would be required for doing so (such system would not be applicable for this project though as the engine has to support a vast variety of games).

by Subr3v (noreply@blogger.com) at August 11, 2014 10:07 PM

August 10, 2014

ScummVM News Headlines

Inherit the Earth Turns 20 — Video of New Game in Series Released

This year is the 20th anniversary of the release of the classic video game Inherit the Earth: Quest for the Orb. The Wyrmkeep Entertainment Co. has announced that it is developing a sequel entitled Inherit the Earth: Sand and Shadows.

This all-ages adventure game is set in a world of humanoid, anthropomorphic animal characters. The story follows Rif the Fox as he tries to confirm the rumors that an important relic of the legendary humans has survived and who is responsible for the relic's recovery. Unfortunately, there are sinister forces involved in the rumors — ones that endanger Rif, his friends, and his society.

"Inherit the Earth: Sand and Shadows will be enchanting and thrilling game for all to enjoy, with subtleties and hidden depths that can be appreciated by older players," said company president, Joe Pearce. "With the help of the backers to the funding drive, we expect to release a great game mid-2015."

A video demo has been released on the game's website at http://InheritTheEarth2.com. The video provides a preview of the art, animation and play experience that will appear in the product.

In conjunction with this announcement, the company has launched a funding drive on Kickstarter to help in completing development of the game. Information about this drive can be found at http://InheritTheEarth2.com/kickstarter.

by sev (nospam@scummvm.org) at August 10, 2014 12:00 AM

August 08, 2014

Joni Vähämäki (Akz) - GSoC

Bug squashing

With all the major feature implementation tasks completed, this week I focused mainly on fixing any remaining bugs I could find. Klusark was kind enough to do a full playthrough of the game in ResidualVM, which revealed a number of issues of varying severity. Some of these issues were blockers which prevented progression in the game at certain points. These should all be resolved now, and on current master the game should be completable from start to finish again.

Here's a brief summary of the issues I resolved this week:
  • Guybrush got stuck when attempting to lure the fish on Lucre island into the scupperware box, preventing progression in the game
  • The game got stuck when giving the earrings to the Dainty Lady figurehead
  • Saving and then restoring a savegame caused lighting to break
  • Saving and restoring caused a crash due to broken shadow initialization
  • Guybrush faced the wrong way after the Voodoo Lady summons the items from the heirloom chest
  • Some of the ships and the water at the harbor on Melee island were rendered incorrectly
  • Guybrush was invisible in the heirloom cave, and the light shaft effects were drawn incorrectly
The last two issues were the most interesting ones, so I'll discuss those a bit next. Let's look at a before-and-after comparison from the Melee Island harbor.


Several issues can be seen in the screenshot of the old version on the left. The color of the waves is too dark, the water splash sprites are drawn over the ship and the rowboat, and the bottom of the ship is not clipped correctly.

In debugging these issues, I used Apitrace in order to figure out how exactly the original game forms the final picture. Since the game has an OpenGL renderer (activated with the parameter -gl), we can use Apitrace to extract the list of OpenGL function calls as well as the OpenGL state on each drawn frame. By examining the trace I found that ResidualVM was drawing some of the sprites in a different order than the original game, and for some sprites depth testing was enabled while it wasn't in ResidualVM. Also, the original game draws mask sprites to clip the ship and the rowboat to the correct shape, which were not drawn in ResidualVM at all.

The mask sprites visualized. With additive blending the black bits become transparent.
When actors (including sprites) are about to be drawn in EMI, they are first sorted into descending order by their sort order, which is a per-actor integer field that can be controlled from the game scripts. When an actor is attached to another, the actor's sort order will be overridden by the parent actor's sort order. This is what happens when the water splash sprite is attached to the ship sprite. However, after the sprite is attached, the scripts then set a new sort order for the sprite. In the original engine this value overrides whatever was derived from the parent, but in ResidualVM the sort order was not updated, which caused the sprites to be drawn in wrong order. Updating the sort order even if the actor is attached fixed this issue.

The rest of the issues were mostly related to incomplete parsing of sprite and model data files. I discovered flag fields in the sprite data, which control whether depth and alpha testing should be enabled for that sprite, and whether additive blending should be used or not. I also found a similar flag that controlled the blending mode in the model data. I discovered these mostly through trial-and-error, by changing suspicious-looking bits in the data files slightly and then loading up the original game to see how the changes effect the end result. Setting the correct blend mode for models fixed the water color.

To enable drawing of the mask sprites, I had to disable a piece of old, temporary code that simply skipped drawing of any sprites with "mask" in the name. I assume this was done because if incorrectly rendered, the mask sprites looked ugly and only cluttered the image (see the image above). Now with the blending and sort order fixes in place, the masks did produce the correct result, though.



This is the heirloom cave before and after my changes. The left one is fairly obviously broken: Guybrush is invisible, the light shaft effects look ugly, and shadows are missing. Fortunately the light shaft effect was corrected by the previous model blend mode fix.

Guybrush's invisibility was caused by another seemingly temporary hack in ResidualVM, which disabled drawing to the color buffer if an actor's sort order was greater or equal to 100. In the cave, Guybrush's sort order is set to 100 in the scripts, which caused him to become invisible. The original engine doesn't seem to do anything similar, so I concluded that this behavior was wrong.

The cave set also led me to discover another previously unknown field in the set shadow data. The field is a string, which specifies a name of a light in the set. When this string is present, the shadow projection point should be the light's position, instead of whatever is stored in the shadow data. After parsing the light name and implementing this behavior in ResidualVM, the shadows now work correctly in the cave also.

These fixes can currently be found in this branch.

by Akz (noreply@blogger.com) at August 08, 2014 10:47 PM

August 05, 2014

Lukasz Watka (lukaslw) - GSoC

Mini-games and bug fixing - part two

Hello everyone!

I spent this week fixing bugs that still had left in game code and I can't believe that there are so many of them ;) I'm pretty sure that you can easily find some more, but let's talk about fixed ones now.

I reworked whole Animation class, which felt very complex at the beginning, so I skipped this task of the project at that time and work on it now.

Some frames of sprites in Prince need decompression process before drawing them. Initially, specific frame was unpacked every time the game wants to draw it, which for looped animations (like background animations) wasn't optimal.

At first attempt I changed loading function of Animation to decompress all frames of it when it is used for the first time, so every frame was unpacked just once. It turns out that this wasn't the best solution. Unpacking about 300 frames during the gameplay, not in location loading, can freeze the game for a while and player can see it. I decided to change this conception to find a golden mean for it. So now, each frame is decompressed just once and it's stored for later use, but it's done when game draw it for the first time, so it's not loading all frames at once. I made Visual Studio performance test for this solution and it looks like everything is working well now.

Next part that I was trying to finish this week were mini-games. I was able to fix four of them: "clip-clap" with bartender, one-armed bandit, "Mr. Sun puzzle" and "Throw a rock" . I don't want to spoiler a lot, so here are just a few screen-shoots of them:

"Clip-Clap" with bartender
Mini-game

One-armed bandit
Mini-game

"Mr. Sun puzzle"
Mini-game
"Throw a rock"
Mini-game

I still have to implement last one, which appears at the end of a game.

Rest of things that I fixed this week:
- hero special animation drawing (position of animation and last frames)
- hero running
- inventory  - saving, swapping, opening and new item adding animation
- German texts drawing
- background script interpreter during dialog-boxes
- cursor after loading

by lukaslw (noreply@blogger.com) at August 05, 2014 06:16 PM

Peter Bozsó (uruk) - GSoC

Another avalanche

Hi everybody! :)

As I mentioned at the end of my last post, from now I'll work on my previous GSoC project, Avalanche. As you can see on it's wiki page if you click on the link, there are still much and more to do until not only the game is completable but actually the engine itself is complete.

I already started a new branch and started my work with a quite great deal of refactoring and reworking the drawing of sprites. Now they are fully handled by my putImage() implementation, what is really similar to Pascal's. (Yes, I know that there a couple of commits with CGE2 tags, my bad, they'll be amended before the merge.)

From now, you can take the TODO section of the wiki page as a listing of milestones for the remaining two weeks of GSoC. I'll do my best to erase as much as I can from that list. Today, during the refactoring, I fixed half of the Shoot em' Up - the display of the heads of shot people in the pallets were not right at all. Now, using drawSprite() - which uses the brand new putImage() -  it's all right. Besides that, there's still a little graphical glitch in it regarding Avalot's walking - it's a bit too robotic at the moment. To be fixed as well. :)

Finally, I decided I will take care of the rest of the main menu this week. There's still a missing "pushed in" state for the buttons, and several menu items are just placeholders, selecting them does nothing, since they are not implemented yet. That'll be my first concern from now.
See ya guys!

by uruk (noreply@blogger.com) at August 05, 2014 12:02 PM

August 04, 2014

Stefano Musumeci (subr3v) - GSoC

Dirty Rectangle System Pt 4

In the past week I've been working on the last two tasks for dirty rects:
The first one was implementing a system that allowed to clip a draw call and only render a portion of what's supposed to be drawn, I implemented this in three different ways, based on the type of the draw call:

Blitting draw calls were implemented with a scissor rectangle logic inside the blitting module: this allows the clipping to be very fast as the clipped parts are skipped completely.

Rasterization draw calls are implemented in a different way: this time the scissor rectangle function is implemented on a pixel level, which means that every pixel is checked to be within the scissor rect before being written to the color buffer: this allows the dirty rects system to ignore everything that is outside the dirty region and thus manages to not cover regions that shouldn't be touched that frame.

Clear buffers draw calls are clipped with a special function inside FrameBuffer that only clears a region of the screen instead of clearing everything.

This covers the implementation of the first sub task: the second one was to detect which regions of the screen changed and output a list of rectangles that need to be updated.

This task was implemented by keeping a copy of the previous frame draw calls and comparing the current frame draw calls with the previous one: this comparison tries to find the first difference between the two lists and then marks as dirty every rectangle that is covered by subsequent draw calls.
Once this list is obtained with this method I also use a simple merging algorithm to avoid re-rendering of the same region with overlapping rectangles and also to reduce the number of draw calls.

What happens after I have this information can be described with the following pseudocode:

foreach (drawCall in currentFrame.drawCalls) {
    foreach (dirtyRegion in currentFrame.dirtyRegions) {
        if (drawCall.dirtyRegion.intersects(dirtyRegion)) {
           drawCall.execute(dirtyRegion);
        }
    }
}

There's only one problem with this implementation: I have found that EMI intro sequence is not detected properly and causes some glitches whereas everything else works fine.

From what I've seen though this method isn't helping the overall engine performance by much: as most of the time is spent in 3D rasterization this system doesn't cope well with animated models that change very frequently and fails to be effective.

I will keep you updated with how this progresses in the next blog posts, stay tuned for more info!

by Subr3v (noreply@blogger.com) at August 04, 2014 10:15 PM

August 03, 2014

Peter Bozsó (uruk) - GSoC

Merging #2

This time: CGE2!!! :)

You can follow my pull request here!
I am very happy and very proud of the four of us that we got to this point that early. Great work guys, we deserve a beer! ;)
On the other side, my last week was spent mostly with cleaning up TODO-s, FIXME-s and CHECKME-s in the engine's code.
All the while, Paul fixed our FXP implementation, so the ever haunting bug concerning pathfinding is finally fixed.
Also, as David supplemented me with a couple of Valgrind error logs, I was able to fix almost all of the memory leaks until now. I write "almost", because David wasn't able to play trough the whole game yet, so issues could still arise, but I am pretty optimistic about things now. :)
The autosave functionality and the Return to Launcher support are also added to CGE2 now, so we can say: the engine is finally complete!

For the remaining weeks of GSoC, I'll implement the rest of my last summer's project, Avalanche, and of course, I'll keep a very keen eye on my pull request to fix every problematic part as soon as possible.

See you soon! :)

by uruk (noreply@blogger.com) at August 03, 2014 03:28 PM

Merging

Hi everybody!

After another bigger break I proudly announce you the pull request of Avalanche engine on GitHub!!!
In the last few days Strangerke and me worked a lot to make the engine more coherent and readable, and we were even able to implement most of the sounds and the harp-playing mini-game alongside it.
There are still lot to do with the game, so my work clearly won't stop by the end of this year's GSoC. If you want to be kept well informed, I suggest you to check the wiki page of the engine regularly, as well as keep on reading this blog, because I won't stop writing posts about my progress neither. (Even if not weekly, thanks to school... but as frequently as it is possible.)
At last I want to say thank you to everyone, especially to my mentors: Strangerke and fuzzie. These two, and practically the whole ScummVM team helped me so much developing my engine that I can't even describe the gratitude I feel toward them! It's a great team to work with and being part of it. I am also very thankful to Google as well since they made my whole project possible with their financial support. Thank you guys, you are all awesome! :)

by uruk (noreply@blogger.com) at August 03, 2014 02:26 PM

July 31, 2014

Joni Vähämäki (Akz) - GSoC

Fixing the music in the PS2 version

After last week's progress, the sound in the PC version of EMI when run in ResidualVM was close to perfect. However, the PlayStation 2 version of the game still wasn't playing any music. Although I haven't focused much on support for the PS2 version so far I decided to look into the PS2 music issues, because I was ahead of schedule and this was one of my stretch goals.
PS2 version of EMI running in ResidualVM.
Much of the groundwork for PS2 support has already been done by previous contributors. For example, the SCX sound format used for the sounds in the PS2 version is supported (although the implementation currently doesn't stream from the disk). However, the music wasn't playing because a mapping from music state numbers to filenames was missing.

EMI (like other iMUSE games before, I presume) assigns an integer state number for each music track. The game scripts tell the engine which state should be playing at any given time by calling the engine function ImSetState, which takes a state number as parameter. In the engine, we then need to be able to map the state number to the correct music file.

In the PC version this mapping is stored in the file FullMonkeyMap.imt, but unfortunately in the PS2 version the mapping is hardcoded into the PS2 executable.

To locate the data inside the PS2 executable, I used the excellent PS2 disassembler tool ps2dis. Firstly, after starting up ps2dis and opening the executable, I invoked the static analyzer from the Analyzer menu. This will add function labels and track data references, making the disassembly more understandable.

Next, I opened the "Jump to Labeled" dialog with Ctrl+G. This dialog lists the strings stored in the binary. Scrolling the list down a bit revealed this:

The "Jump to Label" view in ps2dis.
The strings that end with ".scx" are the music filenames. If we jump to the location where one of the strings is stored, We can then use "Jump to Next Referer" with F3, which will take us to a location in code that references this data. For the music filenames there is only one location referencing them.

A section of code that references the music filenames.
This looks promising! The code here grabs the filename plus some unknown data and passes this information to a function. There are exactly 125 references to the filenames here, which is the same as the number of music states in EMI. My assumption is that the code here builds the state to filename mapping entry by entry counting up from state number 0.

With the state number to filename mapping figured out and implemented into ResidualVM, the PS2 version now plays music as well. These changes are now included in PR #972. With some additional fixes introduced in PR #975, the PS2 version is now fully playable, although some (mostly graphical) issues still remain.

by Akz (noreply@blogger.com) at July 31, 2014 05:54 PM

July 29, 2014

Lukasz Watka (lukaslw) - GSoC

Saving and bug fixing - part one

Hello everyone!

I spent most of this week trying to find and fix bugs that had left in game code and to implement last engine functions. I'll write about the most important ones.
I also implemented basic game saving / loading, so it should speed up my testing work.

First thing that I managed to finish this week is the map location. It's a little bit different from normal locations. There was a problem with masks and objects, which should hide undiscovered parts of map.

Objects (edges of map and black shapes) are drawn on background surface only once, at location loading, and they are removed from objects list after it. This new surface become a current background, so when masks are drawn (check here), they don't show as discovered parts. In this location masks are triggered only by hero and they are used to hide him when he's walking across unexplored places.

Map location - temple exploring
Left - before  / Right - after

Second thing that I implemented was algorithm for map exploring animation. I changed the original one a little, but final effect should still be the same or very similar:

Map during exploring - Temple
Left - original / Right - ScummVM



I was working on implementation of blackPalette() and setPalette() functions.
They are used when hero changes location and they allow to gradually change color palette from normal to black and vice-versa.

Location no. 1 - Graveyard
Palette blackout


Game saving and loading is working only during the runtime now. You can't load your save-game from a launcher, but it's working similar to original game (you always start from the beginning in it and you have to skip intro animation to load your game). I'll think on updating it later, when everything else will be done.



I aslo made huge update in sounds and midi music part. I get rid of all memory leaks in it and now all sounds (not only hero and mobs voices) are playing correctly. We can hear gravedigger polishing graves or owl sounds for example.

Rest of things that I fixed this week:
- position of texts in wider locations and fix for inventory texts
- hero special animation drawing (still without shadows)
- mob priority list (order of mobs names drawing)
- bear form animation crashes
- pathfinding update
- blocked RMB menu on map mobs

I'm going to work on fixing rest of existing bugs this week and maybe implement rest of ScummVM's Advanced Engine Features.



by lukaslw (noreply@blogger.com) at July 29, 2014 08:50 PM

July 28, 2014

Stefano Musumeci (subr3v) - GSoC

Dirty Rectangle System Pt 3

In the past days I've been working on dirty rectangle system and I wanted to share some results I have achieved in this blog post:

First of all, I had to introduce a new type of draw call that turned out to be needed: Clear Buffer; this type of draw call just clears either the color or the z buffer (or both, if needed) and it always has a full rectangle screen as dirty region.

When I had all the draw call types implemented I just had to make them work in deferred mode: in order to make this possible I had to track down all the state that was needed by TinyGL to perform that specific draw call and then store it so that I could apply this state before performing the actual drawing logic.
Having done this, sub task 1 proved to be easily implemented as I just had to store all the draw calls in a queue and then perform them sequentially when the frame was marked as "done".

With sub task 1 done I then proceeded with the calculation of which portion of the screen a draw call was going to affect: calculating this was rather easy for blit draw calls but it turns out that calculating what a rasterization draw call is going to affect isn't very complex either: I just had to calculate a bounding rectangle that contained all the vertices (after those were transformed to screen space).

Since I had all the information about the dirty regions of the screen I wanted to display this information on the screen so that I could see which part was affected by which type of draw call so here's some screenshots
(red rectangles are blitting draw calls while green rectangles are rasterization draw calls):


Now I only need to work on the last two sub tasks: 
  1. Implement the logic behind draw calls that allows the caller to specify a clipping rectangle for that specific instance.
  2. Implement the logic that detects the difference between draw calls and performs clipping on them.
But I'll write more about these as the work progresses, as for now... stay tuned!


by Subr3v (noreply@blogger.com) at July 28, 2014 05:15 PM

July 25, 2014

Joni Vähämäki (Akz) - GSoC

Improving the music playback

For the past week I've been working on a number of improvements to the EMI sound system in ResidualVM. My change set in PR #972 improves especially the music playback in the PC version of the game.

Firstly, the music playback now starts at the correct position of the track, and the correct sub-section of the track is looped. This is because the music player now respects the cue point data which is stored in files with the file suffix ".jmm" alongside the actual MP3 music files.

The .jmm files may contain 'start', 'jump' and 'end' cues. The 'start' cue specifies a position in milliseconds where the music track should start playback. The 'jump' cue specifies two positions on the track. Once the first position is reached, the playback will jump to the second position. This cue is typically used to loop a sub-section of the music track. If the JMM file does not specify a 'jump' cue, the track does not loop (an example of this is the chapter screen music). The 'end' cue seems to always have a value of -1 in EMI, so I chose not to implement handling for it at this time.

Secondly, music syncing is now implemented. In some parts of the game, when the music track changes the new track should start from the same position where the previous track ended. Typically such synced tracks are slight variations of the same composition. For example, when Guybrush is close to the fountain in Melee town (set mel), the music changes to a version of the Melee town music with a sound of flowing water mixed in.

The information whether a music track should be synced with another track or not is stored in a file called FullMonkeyMap.imt. This file maps music track id numbers (which are referenced from the Lua scripts) to sound files, and specifies some parameters for each track. One of these parameters is called "sync", and has an integer value associated with it. A value of 0 seems to indicate that the track should never be synced. Otherwise, if the sync value matches the sync value of the track that was playing previously, the track will start from the same position where the previous track was at the time of transition.

Another improvement to music playback is when the music track changes, the music now transitions with a linear cross-fade, instead of instantly cutting to the new track. This makes the transitions sound less abrupt, and matches the behavior of the original game.

by Akz (noreply@blogger.com) at July 25, 2014 08:45 PM

July 22, 2014

Lukasz Watka (lukaslw) - GSoC

Pathfinding and hero movement

Hello everyone!

I was working to finish pathfinding part and implement hero movement animation this week.

I made huge clean-up in code and optimized an algorithm so it's not hanging whole game now. I used Visual Studio performance test to find slowest part of code. I also found and fix several bugs in pathfinding part, so it's not causing crashes anymore and there are no memory leaks in it. I can say it's working in 99% now, but it still need some testing. ;)

I updated it to allow mouse-clicking on places where hero can't directly go and to find closest point for destination instead. Pathfinding is also working correctly in wider locations now.

Last function to implement was scanDirection(). It used calculated array of path points to create array of directions for hero animation.

After finishing engine part of pathfinding I updated script part functions - O_RUNHERO, O_MOVEHERO, O_CLEARPATH, O_SETPATH and O_LOADPATH, so hero is walking to objects or mobs before he inspects or talks with them. "Walk to" option in right mouse button menu is also working now.

I made big changes in part of code that I had implemented at the beginning of my project - most in showHero(). It's a function that, among other things, make use of path cords and directions arrays calculated in pathfinding part. It counts hero animation frames and change animation according to current direction. It allows to turn hero during the path and to speed up his movement by skipping some of points on the path.

You can watch my progress on video right here: https://www.youtube.com/watch?v=nDPYoZoO3mI





by lukaslw (noreply@blogger.com) at July 22, 2014 06:11 PM

Stefano Musumeci (subr3v) - GSoC

Dirty Rectangle System Pt 2

In this second part of the Dirty Rectangle System series I will describe the different categories and types of draw calls that are implemented in TinyGL, what is required for them to be performed and thus the state that needs to be tracked down and saved.

Since TinyGL is an implementation of openGL the most important category of draw call falls into the category of rasterization: that is, when vertices are issued inside tinyGL's state machine they are then transformed into screen buffer coordinates and then rasterized into triangles or rendered as lines.
However, since 2D blitting is implemented with a different code path we should regard this as a second category.

So we end up having two categories of draw calls: rasterization and blitting; those categories contain different cases though, so they should be separated in types:
Rasterization can either be a triangle rendering draw call or a line rendering draw call, whereas Blitting can occur on the screen buffer or the z buffer.

I will implement those two different Categories as two subclasses of DrawCall but I will differentiate the logic behind the types inside the implementation of those two classes instead of creating more indirection (as they share 90% of the code and only a few things are to be implemented differently between types inside the same category).

As this task is quite complex and elaborate I decided to split everything in 4 sub tasks that will help me track my progress and make sure that everything is working on a step by step basis:

  1. Implementing a system that store and defers draw calls instances until the "end of frame" marker function has been called.
  2. Implement a system that detects which part of the screen is affected by each draw call and shows a rectangle on the screen.
  3. Implement the logic behind draw calls that allows the caller to specify a clipping rectangle for that specific instance.
  4. Implement the logic that detects the difference between draw calls and performs clipping on them.
The next post will cover the implementation of those DrawCalls subclasses more in depth so stay tuned if you're interested in this!

by Subr3v (noreply@blogger.com) at July 22, 2014 11:13 AM

July 21, 2014

ScummVM News Headlines

ScummVM 1.7.0 "The Neverrelease" is out!

A year has passed and ScummVM 1.7.0 is here.

With this release we have added support for 5 completely new games. These are:

  • The Neverhood
  • Mortville Manor
  • Voyeur
  • Return to Ringworld
  • Chivalry is Not Dead

Also, we have updated the MT-32 emulator, added an OpenGL backend, improved many aspects of the GUI, enhanced the AGOS engine, made Urban Runner's videos less CPU-demanding, fixed tons of bugs in dozens of SCI games, improved sound in Loom and Indiana Jones and the Last Crusade and improved platform portability for the Tony and Tinsel engines.

But this is not all. We have added experimental support for the OUYA console (we couldn't add GCW-Zero support simply because sev still awaits his console from Kickstarter), made major improvements to the PS2 port and merged the Bada with Tizen ports.

The full list with all changes mentioned can be found in our release notes and the release can be obtained as usual from our downloads page.

Everybody Way Oh!

by sev (nospam@scummvm.org) at July 21, 2014 12:00 AM

July 05, 2014

John Willis (DJWillis)

ScummVM: ‘pre1.7.0’ Testing/Preview Builds

As a few people have noticed I have been rather lacklustre on my ScummVM backend releases of late, especially for the venerable old GPH devices (I did manage to get current OpenPandora releases out).

I won’t bore people with details and whatnot, real life, health and time, but without further delay I present 1.7.0 testing builds for all my current ScummVM backends (GP2X, Wiz, Caanoo and OpenPandora). Taken from GIT commit c36867d,

These builds exist purely to get some feedback and testing from the community, especially on devices like the Wiz as I am coding blind since mine died for good (does anyone have one to sell?).

I feel the builds are in a pretty decent state but it would be nice to pick up any snags over the next week to see if I can clean them up before the next official ScummVM release.

If your not interested in testing and providing feedback (and dealing with the odd issue) please stick with the current official releases.

These are not robust, fully tested release builds but I am also pretty sure they will not eat or damage your device Winking smile.

Note: Please don’t mirror or hotlink these releases or put them on download services but rather, direct people to this page.

This helps me ensure that users always have the most recent versions and cuts down on me being requested to support ancient or test releases.

Also note that these test releases are not officially (or unofficially) supported Winking smile.

All the appropriate engines enabled in configure for release are included in this build. That said, don’t magically expect the high resolution games to work well on the GPH devices.

Specific restrictions:

GP2X: Slow with some of the newer games and starting to hit limits on the old ARM9 device but still very usable. Need to revisit plug-ins if I have motivation.

GP2XWiz: My GP2XWiz has died so this build is totally untested . There is so much in common with the Caanoo that I am fairly sure this build will work. Please test it and give me some feedback.

Caanoo: The build seems fairly solid.

OpenPandora: Likewise, the build seems fairly solid.

If you find issues please report them.

Providing feedback:

If you would like me to consider a feature or fix a bug help me to help you by ensuring the reports end up recorded in official places.

Downloads:

Please ensure you download the correct version for your device:

Installing:

GPH Devices:

Extract the contents of the archive to the game folder on your SD card, ensuring that you have a “scummvm.ini” in your game folder and the rest of ScummVM in a “scummvm” subfolder.

Launch “ScummVM” from the main launcher menu to run.

Review the README-GPH for more information.

OpenPandora:

Just extract  and dump the PND somewhere handy as normal.

by DJWillis at July 05, 2014 10:04 AM

 

curved edge   curved edge