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.

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 23, 2014

Peter Bozsó (uruk) - GSoC

Sounds

Hi all! :)

During the past week, I mostly spend my time with the missing/badly working sound parts of my engine. The first and most nasty problem I had to solve was that in the original, every animation is blocked while a sound was playing. Clearly, it wasn't the case with my version of the game until now. To specify the problem, it's not true for every sound, only for the the speech of the characters. To achieve that, I had to add a block to the script parser of the engine, so there won't be any action until the actual sound is fully played out. Luckily, that checking of the blocking flag was already in the original as well as the setting of it to true. The tricky part was to decide where, when and how to reset this flag. Again, ScummVM's very friendly library came to my rescue. In the main loop of the game, I simply have to check the responsible sound handle:
void Sound::checkSoundHandle() {
    if (!_vm->_mixer->isSoundHandleActive(_soundHandle))
        _smpinf._counter = 0;
}
As you can see, if it's no longer active - there's no sound playing at the moment - I set the counter back to 0. This counter tells our LoopingAudioStream instance how many times it has to loop when playing the given sound, and the script parser checks for this number and doesn't do anything if it's a positive number.

After this issue fixed, my attention was fully paid to the buttons on the toolbar what are connected to sound manipulation. The "hard" part here was not the actual implementation of the buttons, but the fact that I have to pay extra attention to them so they keep in synchronization with ScummVM's Launcher's and Global Main Menu's sound settings.
You can see the mentioned buttons on the toolbar with a cute pink outline around them on this picture:
Until now, I was only able to achieve complete functionality (and parallel behavior with ScummVM's options) with the music on/off button. (This is the big grey round plate in the middle with a note on it.) Currently, I am working on the speech/text mode switches (to the right, with two blue arrows above them), so they'll take into account the global options in the Launcher regarding speech only/text only/both modes.

Besides that, Arnaud is still progressing nicely with the translation. It's not far from being complete, but there is still a very nasty blocking bug concerning the dentist's scene we are looking at almost constantly.

For the next week, I'll finish with the sounds completely, including the two remaining switches on the toolbar. Then I'll keep on refactoring the code - what I already started to do here and there -, and fix memory leak issues as well as other persisting bugs. I already paid attention to eliminate all the remaining stubs in the engine, but there are still a bunch of them in the script parser. I plan to take care of these too as soon as possible.

See ya next time! ;)

by uruk (noreply@blogger.com) at July 23, 2014 04:01 PM

July 22, 2014

Joseph Jezak (JoseJX) - GSoC

More on Text Positioning

Continued from the previous entry.

Let's take stock of the current state of the text positioning changes after the last blog post. First, let's look at the differences in the set wed when Guybrush says "There's an enemy pirate fighting over there.":

State of the text difference at the start of this post in the set wed
With the changes from before, we can see that there is less difference than when we started, but that the text for Guybrush's speech bubble is positioned to the right by 1 pixel and towards the bottom by 5 pixels. Likewise, the text for "Look at enemy pirate" is closer, but still not quite right. It appears to be 11 pixels too high, towards the top compared to the retail version.

Another place with a similar issue is the text at the top of the inventory. It appears that the text is drawn 12 pixels too high, resulting in this difference:
 Misplaced Inventory text
As an aside, the differences in object rotation in the inventory appear to be related to be related to the rotation and attachment work I've been blogging about. That work wasn't in this branch when I took the screen shot!

Anyway, there's definitely a problem with the placement of text on the Y axis, with a similar problem displayed in both sets. As it turns out, there's code that specifically moves the text in the Y direction by 12 pixels in ResidualVM. This code is found in textobject.cpp and appears to have been added with this commit. Commenting out this adjustment results in the text for the inventory being placed in the correct location and bringing the command line in the set wed within 1 pixel of the correct location. Let's take a new screen shot with this change:
Current text difference at this point
As can be seen, the action sentence at the bottom is very nearly correct and only off by one pixel. However, the speech bubble got worse. Now, the ResidualVM text is still 1 pixel to the right, but 17 pixels lower than it should be.

My first thought was that there was simply a blank line inserted below the text, but the font height for EMI was 26 pixels, not 17. I next checked the bounding boxes for the actors to see if they made sense by drawing a green line around Guybrush representing the bounding box whenever he spoke. Here's what the output of that was:
Guybrush's bounding box
However, in order to get the bounding box to draw properly, I had to subtract the Y components from 480. In order to make the code simpler, I removed the subtraction from the Y component when computing the bounding box from the bounding box calculation and re-ran the test. Here's the result after modifying the bounding box code:
The green line is the bounding box for Guybrush's actor
Although the bounding box looks a little worse (see: Guybrush's feet and hair), I checked the text position with this new bounding box and found that it was off by 26 pixels, which if you remember, was the height of the font. Subtracting 1 from the number of lines that the text was pushed up by gets the fonts for this scene rendered very closely to the original:
Very close now!
We can see that the fonts are still off by 1, but for now, this is close enough! So, let's check to see if there are problems in other scenes. Unfortunately, there are:
The text is in the wrong place again!
Here, you can see that Guybrush's speech is rendered at the wrong place in the set gmi.

As a check, I also tried this branch with Grim Fandango and found that it too had fonts drawn too low, with text 13 pixels too low and offset by 2 pixels to the right for the top line and 1 for the bottom line:

Grim also has differences in the font location
As an aside, bgK also tested this with the French version of Grim, which was reported to be problematic with using the kerned font sizes. I'm happy to say that the crashing issues from that appear to be resolved!

In the next blog post, we'll take a look at these two issues and see if we can resolve them.

by Joe Jezak (noreply@blogger.com) at July 22, 2014 07:32 PM

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

Joseph Jezak (JoseJX) - GSoC

Making the Correct Rotations Work

Continued from the previous entry.

In the previous posts, I've managed to get the relative position and rotation values to match the ones from the retail version of EMI. In this post, I'm going to discuss how to present these rotations on the screen, fixing the messed up image we left off with in the last post:
Where we left off...
Let's start by taking a look at the apitrace output of this scene again. I started by running the retail version of the game with the options "-w -gl" to start in a windowed mode using OpenGL. After capturing the apitrace of jumping ahead in the script and moving to the set pph using the jump target "160",  I then loaded the trace into qapitrace. First, I had the trace build thumbnails of all of the frames so that I could identify the first frame that drew the scene pictured above. With the scene identified, I then looked through the data captured for this frame to inspect the rotation matrices that were responsible for rotating and placing the rendered objects.

I decided to focus on the trap first because it is a constant object in the scene and isn't moving. To find the part of the trace responsible for drawing the trap, I browsed through the API calls, checking the Surfaces tab to see if the trap had been rendered yet:
APITrace output, examining the drawing of the trap
With this section of trace found, I could then inspect the OpenGL state (in the Parameters tab) when this was rendered, providing us with the transforms used to place the object in the scene. With these transforms in hand, I then proceeded back to the ResidualVM code and checked the matrices against the ones I found in the trace. From this analysis, it appears that the Projection Matrix is correct, but the ModelView Matrix is incorrect. Let's take a look at what ResidualVM is doing to arrive at the ModelView Matrix for the model of the trap.

First, I inspected the value of the ModelView matrix at the start of drawing the trap and found that it was set to an identity matrix. This was then multiplied by another matrix using glMultMatrixf, then translated using glTranslatef, then multiplied once more, again with glMultMatrixf. In the retail version, the only command run is to load the matrix using glLoadMatrix, indicating that the matrix was probably prepared ahead of time or done in software. That said, with the correct result for the ModelView matrix, we can go back through the steps taken in ResidualVM and correct the problem.

So, where in the code do we find this sequence for setting the ModelView? In the OpenGL path (engines/grim/gfx_opengl.cpp), there's a function called startActorDraw which prepares the ModelView matrix for drawing the object. In the non-overworld case, it multiplies the current camera rotation, then translates with the camera position. Then, it takes the Actor's final matrix, transposes it and multiplies the ModelView by the result. There are a few likely possibilities for where this implementation is wrong:
  1. The camera rotation is wrong because we changed the Euler Order for the actor as part of this fix
  2. The actor's final rotation matrix is incorrect
Since I suspect that the final rotation matrix is correct because of the work we've done up to now, I'm going to first start with checking into the camera rotation. To begin, where does the camera rotation come from? In the same file, there's two functions that are responsible for setting up the camera, positionCamera and setupCamera. When the set is loaded, there are a number of parameters that define the camera for each setup in the set:
  • position - The point position of the camera
  • interest - The point that the camera is pointed at
  • roll - The roll of the camera
  • fov - The field of view of the camera
  • nclip - The near clipping plane of the viewing frustum
  • fclip - The far clipping plane of the viewing frustum
However, after some investigation, I found that the interest and roll parameters are really just quaternion components, unlike in Grim. The existing ResidualVM code was using them as Quaternion  components, but they were using the original Grim Fandango names for them.

Also, when creating a set with these parameters, the retail version of EMI creates an actor object that's kept as part of the setup to represent the camera. This allows it to keep track of the position and rotation information in the same way as the actors in the set.

Following the usage of these parameters in ResidualVM to the function setupCamera, I compared the calculated frustum to the apitrace results and found that ResidualVM was computing this correctly. So the issue was most likely related to the positionCamera function. So, how can we fix it?

I started by examining the retail version again in IDA Pro and found that there are a number of camera functions to retrieve the camera rotation and position. Unfortunately, these weren't yet functional in ResidualVM, so I added them as a part of this work. These functions are:
  • GetCameraYaw
  • GetCameraRoll
  • GetCameraPitch
  • PitchCamera
  • RollCamera
  • YawCamera
To implement this functionality, I decided to keep the rotation of the camera internally as a matrix, and calculate the Euler Angles as needed. When writing out the value for saved games, I use the Quaternion representation of this rotation so that it's compatible with the existing version. Why did I choose to keep the rotation as a matrix? In all of the graphical code that uses the camera rotation, it previously had to convert between a quaternion and a matrix each time the rotation was used. By keeping the rotation as a matrix, we avoid that overhead for the common case and only convert when reading or writing the setup rotation values for saved games. After checking these functions against the retail version, we see that the camera rotation values are placed and rotated properly.

Still, at this point, after all of this work, the graphics themselves haven't been fixed. We haven't change any of the output since the beginning of this post, just the representation in the code. So, how are the rotation matrices computed for display? First, here's the desired ModelView matrix for the trap, extracted with apitrace:

Crawdad Trap: Retail ModelView Matrix
-0.516999-0.2342870.8232990.0
-0.01683430.9644110.2638730.0
0.85582-0.1225620.5025440.0
-2.60927-1.20781-19.28881.0

What can we see just from this inspection? Well, we can see that there's a 3x3 rotation matrix in the upper right corner, and a 1x3 position vector in the last row. Let's compare this with the matrix from ResidualVM:

Crawdad Trap: ResidualVM ModelView Matrix
-0.5425690.212863-0.8125940.0
-0.0168340.9644110.2638730.0
-0.839843-0.1568480.5196760.0
-2.60927-1.20781-19.28881.0

First, we can see that the ResidualVM position agrees with the position from the Retail version of EMI. We can also see that the middle row of the rotation matrix matches, but the others are slightly off. What might be causing this problem? Well, if we inspect the rotation for the trap, we can see that only the Yaw parameter is rotated, which corresponds to a matrix where the middle row is an identity. This explains why the middle row matches! Now, how about the other rows?

Let's start by going back to startActorDraw in gfx_opengl.cpp. I first checked to see what the current value of the ModelView matrix was before this function acted on it and found that the matrix was an identity, but the 3rd row was multiplied by -1. This was caused by the previous call to glScalef(1.0, 1.0, -1.0). I also checked the stored rotation for the trap's actor and compared that with ResidualVM and found that both ResidualVM and the retail version had the same values. With this information in hand, I then tried changing the order of the operations, as a rotation followed by a translation might not have the same result as the opposite operation. In the end, performing the rotation first, then computing the translation resulted in the correct rotation result. Here's the output now:
Looks pretty good?
Awesome! It looks like it's working properly again! How about the pole after detaching? What are the differences remaining in this scene?
I knew something was still missing! :(

At first glance, it looks fine, but a glaring difference remains: the pole! It's completely missing in ResidualVM. It appears that there's still some users of getFinalMatrix which seems to be producing an incorrect result. In the next post, we'll dig into those and see if we can fix those rotations as well.

As an aside, one interesting observation that can be made from the apitrace results is that ResidualVM makes a lot more OpenGL calls to produce the same screen. It appears that in the original version, instead of always drawing each vertex as ResidualVM does, the game instead sometimes passes a pointer to a list of vertices and uses the following sequence to draw the object:

     glEnable(GL_CULL_FACE)
glFrontFace(GL_CW)
glBindTexture
glTexCoordPointer
glColorPointer
glVertexPointer
glDrawElements

This indicates that the original engine passes these coordinates in a list rather than individually. It would probably be a good idea to make the same optimization in ResidualVM as well because as of right now, the original takes ~5k calls to draw the set pph, while ResidualVM takes ~58k. Maybe a later project? We'll see!

by Joe Jezak (noreply@blogger.com) at July 22, 2014 04:26 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 45 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 20, 2014

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

Correction to the shadow data format

After writing the previous blog post about shadows, I discovered that my shadow implementation caused a crash in the House of Sticks at Lucre island. The format of the shadow data in this particular set did not seem to match the format I described in the previous post.

It turned out that my interpretation of the shadow data was wrong. The shadow color is not part of the 'sector reference' structure as I thought before. Instead it is part of the 'shadow' structure. The color is stored after the array of 'shadow reference' structures.

The House of Sticks after correcting the issue.
It appears that in most cases a 'shadow' structure only contains one sector reference. This is why my initial implementation seemed to work. However, the House of Sticks set file contains a 'shadow' structure that references multiple sectors, and in this case my implementation tried read too much data, since it attempted to read a color for each sector reference.

This discovery indicates that a single shadow will always have a uniform color. However, if multiple shadows are drawn on top of each other, this can give the appearance of a single shadow with multiple colors. This happens for example in the Place of Prostheses.

A combination of two shadows with different colors can be seen in the Place of Prostheses.
Since the shadow color is uniform, rendering the shadows is simplified. PR #956 now contains much less changes to the renderer code, as the EMI shadow rendering is now very similar to that of Grim.

by Akz (noreply@blogger.com) at July 20, 2014 11:01 PM

Stefano Musumeci (subr3v) - GSoC

Dirty Rectangle System Pt 1

Dirty Rectangles system is a term used for a specific rendering optimization that consists in tracking which parts of the screen changed from the previous frame and rendering only what has changed.
Implementing this sort of system is part of my last task for Google Summer of Code and it's probably the biggest and most difficult task I worked on so far.

In order to implement this kind of system inside TinyGL, a system that defers draw calls is required; once this system is implemented then dirty rectangles will be as easy as comparing draw call from current and previous frame and decide which parts to render based on this information.

As every draw call needs to be stored (along with all the information to execute it) the best way to implement this is to use polymorphism and let every subclass of DrawCall store whatever information is needed, thus saving space (because only the necessary information will be stored) at the cost of a minimal performance impact due to virtual functions.

This would be the interface of the class DrawCall:

As you can see the class exposes some basic functionalities that are required to implement dirty rects: you need to be able to compare if two draw calls are equals and you need to be able to perform the draw call (with or without a restricting rectangle).

At the moment only a few operations would be encapsulated inside this class, namely blitting (on framebuffer or zbuffer) and triangle and line rasterization.

That's all for the first part of this series of posts, the next one will describe more in depth the implementation of DrawCall subclasses and the problems that arise with encapsulating blitting and 3d rendering operations!

by Subr3v (noreply@blogger.com) at July 20, 2014 06:03 PM

July 16, 2014

Lukasz Watka (lukaslw) - GSoC

Pathfinding - beginning of implementation

Hello everyone!

Great news, someone may actually play Prince when I finish coding it! ;)
If you understand Polish, you can check articles about my project on websites here:
cdaction.pl, antyweb.pl, polygamia.pl, przygodomania.pl, gram.pl, playingdaily.pl, gry-online.pl, polskathebest.pl, gry.interia.pl, osworld.pl

I finally edited and upload video of first location gameplay that I promised you in my previous post.
You can watch it here: https://www.youtube.com/watch?v=Q5bhHKp8Eh8


I'm aware of existing bugs in it, like:
- hero talking animation sync (fix to match currently playing voice)
- hero boredom animation timing (shouldn't start randomly in time of dialog)
- hero shouldn't have dagger equipped from the beginning of a game
- gravedigger's last line before his runaway - "O w morde..." is not playing
And gameplay also lacks working pathfinding, so Prince is standing still whole time, but I'd like to tell you about my current progress with fixing it.

I spend this week trying to analyze, code and then fix most of path-making functions.
It was lots of lines to code and it still has some things that I have to fix but right now it looks like this:

Pathfinding - testing
Path drawing #1

Pathfinding - testing
Path drawing #2

If you look closely you can see white dotted lines that are drown temporary to display array of calculated path coordinates. I'm working on part that allows to find a correct, nearest place for destination when you click on place where hero can't go.

Next step will be implementing scanDirections() function, that will allow to create array of directions for hero walk animation during the path and also updating showHero() function to fix some bugs that I mentioned before and allow hero to actually walk the path.



by lukaslw (noreply@blogger.com) at July 16, 2014 09:09 PM

Peter Bozsó (uruk) - GSoC

Toolbar and memory leaks

Hi guys! :)

During the last week, the most spectacular part of my progress was the implementation of some functionalities on the toolbar. Now, you can switch between normal, colorful display, and "mono-color" mode, which is there to support players with seeing difficulties. Let me illustrate it with two pictures:


Pretty kind of the original developers, isn't it? :) Besides that, thanks to ScummVM's another great feature, now you can enable this colorblind mode not just by clinking the purple sphere on the toolbar (next to Vincent's inventory), but you can also configure the engine right from the launcher, so it always runs in this mode.


To do so, I only had to add this static array to detection.h:

static const ADExtraGuiOptionsMap optionsList[] = {
{
GAMEOPTION_COLOR_BLIND_DEFAULT_OFF,
{
_s("Color Blind Mode"),
_s("Enable Color Blind Mode by default"),
"enable_color_blind",
false
}
},

AD_EXTRA_GUI_OPTIONS_TERMINATOR
};

And just pass it as an argument to the constructor of my subclass of AdvancedMetaEngine. It's quite awesomely simple, isn't it? :)

Another feature I added is that now you can also switch between speech-only and text-only mode using the little ear and eye icons next to the main switch on the right side of the toolbar. Of course, you can still stick with both, simply clicking on the mouth icon above the two. :)

Besides that, my last week mostly spent with fixing various newly found bugs and patching up the engine in different places so it (hopefully) leaks less memory now.
In practice, I will keep on doing that during the next week, since now (many many thanks to Arnaud) all the scenes in the game are reachable and most of them are fully or at least partially translated too. So we are absolutely not far from saying that the game is in a completable state, but there are still a lot of showstopping bugs what need to be tended

See you soon! :)

by uruk (noreply@blogger.com) at July 16, 2014 08:56 AM

July 15, 2014

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

Implementing shadows

Feeling relaxed after a week of vacation I'm now finishing up work on implementing shadows for EMI. This work is now in PR #956.

EMI has two types of shadows: simple shadow sprites (internally called "lame shadows" or "dumb shadows" :) ) and planar projection shadows. The projection shadows look more realistic, but are only used in a few sets. If shadow quality is set to low in the options, only shadow sprites are used.

The screenshots below are taken from the original game. In the screenshot on the left, shadow sprites can be seen under Guybrush and Elaine. The screenshot on the right shows projection shadows cast by Guybrush and the brazier on the deck of the ship. Initially with ResidualVM both shadow types were not drawn at all.


After my previous sprite fixes, enabling the shadow sprites turned out to be very simple. Previously ResidualVM's actor drawing code contained a hack that skipped drawing the costume containing the shadow sprite if shadows were not explicitly activated for that actor with a call to ActorActivateShadow from Lua. After some testing in the original game I found out that the ActorActivateShadow function doesn't affect the shadow sprites at all in the original (instead it is used to toggle projection shadows). After removing the hack, the shadow sprites showed up as expected.

I then moved on to tackle the projection shadows. This turned out to be slightly trickier. Fortunately projection shadows have been implemented previously in ResidualVM's renderers for Grim Fandango, so most of the rendering code could be reused also for EMI. To render projection shadows we need a shadow color, the light position as well as the planes on which shadows are cast on. The first problem was that I didn't know where the original game got this information from.

In Grim, the shadow color, the light position and the shadow planes are set up through Lua code, but in EMI I couldn't find anything similar in the game's Lua scripts. The information had to be stored somewhere else.

The next place I decided to look in was the .setb files, which contain scene-specific information such as camera positions, sectors and lights encoded in binary form. The shadow color seems to change between sets, so it seemed like a fair assumption that the information I was looking for would be stored in the set data.


This led me to the discovery that for sets that have projected shadows enabled, there was indeed some data at the end of the .setb file that was not read by ResidualVM (marked with red in the pic above). This previously ignored block of data contains an array of structures that I call 'shadow' structures here. Each 'shadow' structure contains a name, the light position to be used when projecting the shadow and an array of 'sector reference' structures. The 'sector reference' structure contains the name of a sector within the set as well as the shadow color to be used when a shadow is projected onto that sector.

Once I discovered this data, it was fairly easy to enable the pre-existing planar projection shadow rendering code in ResidualVM also for EMI. The main difficulty was that previously the renderers only supported one global shadow color, but in EMI the shadow color can be set per-sector. I'll discuss this issue and how I resolved it in detail in the next blog post.

With all the issues resolved, it's very hard to tell ResidualVM and the original game apart in most scenes. The screenshots below are from ResidualVM. Compare them with the screenshots of the original above :)





by Akz (noreply@blogger.com) at July 15, 2014 10:41 PM

Joseph Jezak (JoseJX) - GSoC

Positioning textObjects

There are a lot of differences with the positioning of textObjects between the retail version of EMI and ResdiualVM's implementation. Let's take the scene wed and compare the text positions. First, here's the scene in the retail version: 
Retail screen shot from the set wed
And here's the same scene in ResidualVM:
ResidualVM screen shot from the set wed
And finally, here's the difference between the two:
Difference between the two images
We can ignore the ship in the background, since it's moving, and I didn't capture it in exactly the same place. We also can ignore the shadows, Akz has already addressed that problem. That leaves us with the text errors, exactly what we're trying to work out!

While it's obvious to the eye that the text "There's an enemy pirate over there." is in the wrong place and has a different wrapping point, there's also a mismatch between where the text is placed for "Look at enemy pirate".

Additionally, in some cut scenes, with subtitles on, the text is placed in the wrong location. A good example of this problem is the scene during travel to Jambalaya Island, where the exclamations of the crew are drawn right on top of each other! Another common issue is that the text is placed in the wrong place, obscuring the game play. A good example of this is when reading the directions to get to Pegnose Pete's house.

In ResidualVM, text elements are drawn using a textObject. In the Lua scripts, textObjects are created by calling the Lua/C function MakeTextObject. The parameters for the textObject are the string that's going to be displayed and a parameters table, with various options for configuring the text. We can remove this textObject from the screen by calling KillTextObject and passing the handle that was returned by MakeTextObject.  Let's try drawing some text with the retail version of EMI and observe the behavior. Let's start by just writing some text to the 0, 0 coordinate position:

textObj = MakeTextObject("Hello Blog Readers!", { x = 0.0, y = 0.0, font = verb_font, fgcolor = White })

Here's the output of running that command:
There's the text!
An interesting aspect to the positioning of the text is that it appears to be using a coordinate system with a basis in the center of the screen. Next, lets try exploring the extents of the text placement. Do negative values work? (Yes!) What is the highest and lowest X and Y value for placing text that still appears on the screen? (It appears that -1, -1 is the lower left corner and 1,1 is the upper right corner). Is this mechanism the only way text is added to the screen? (Nope, there's also SayLine, PrintLine and other methods, so when debugging, the method used will be important).

With this information in hand, I started by rebasing Botje's changes (to allow the X and Y values to be passed as floats) against the current master. These changes, made the text appear more correct for scenes where the X and Y values are passed from the Lua, such as the directions to Pegnose Pete's House, but this change didn't effect most of the erroneous text placement.

I then inspected the SayLine Lua/C function and found that it sets a variable when X and Y aren't passed in from the Lua script, which has the actor set the position relative to the actor's bounding box. Simply using the other side of the bounding box for the Y position moves the actor's speech to a much more correct location:
After the bounding box side switch
The next task I tackled was the incorrect word wrapping, as seen in the speech bubble, "There's an enemy pirate fighting over there.". Although the ResidualVM version actually looks a little bit better than the retail version here, there are other scenes where the word wrapping is worse, so let's try to fix it!

The word wrapping is done in the function setupText, which is found in the textobject.cpp file. Inside this function, the line width is computed by adding each character width in the line together. Strangely, this uses the maximum value between the character width and something called the dataWidth. Without a comment, it's hard to tell what dataWidth actually means, so, I first started by identifying when this code was added to ResidualVM. This was a harder task than anticipated because the file was moved twice over the course of development. To trace its history, I first reset git to the first commit that moved the file and then, pushed the HEAD of the repository back one more commit. This restored the original version of the moved file and let me explore its history further. After one more file move, I found that this was the commit that added the dataWidth field. Unfortunately, there wasn't much information in the commit message either, so I decided to try to test some strings in the retail version and measure what the width of the displayed text in pixels.

So, it appears that the dataWidth is the actual width of the character, but the width includes adjustments to the spacing (or kerning) between the letters to make them look nice. As an example, let's look at a simple string, "Wa":

     MakeTextObject("Wa", { x = 0.0, y = 0.0, fgcolor = White))

Which results in:
Demonstrating the font kerning
As can be seen, the letter "a" actually overlaps with the letter W by two pixels. It appears that ResidualVM gets this right and does use the correct values for drawing the characters as this matches perfectly with the retail version. So, our issue is with determining when to word wrap, which depends on the width of the rendered text. Let's examine the width variables to figure out what combination results in the correct width being calculated.

For each font character, there's the dataWidth and width sizes, which of these is the actual character width and which is the kerned width? Here's the dataWidth and width values for "W" and "a":

Value      W     
width18
dataWidth21
Valuea
width7
dataWidth9

So, it appears that the "width" value is the kerned value, while dataWidth is the actual size of the font bitmap image. Checking this against the image above shows that the dataWidth values match the pixel size of the letters exactly. So, if we add the dataWidth values together, our characters will be wider than what's actually displayed to the screen. We can fix this by always using the width value instead of the maximum of the two as is done now.

So, let's take a look at the result difference after this change, when Guybrush is speaking the line "There's an enemy pirate fighting over there.":
Getting closer!
We can see now that the lines are the same length now, and appear to be in the correct location on the X axis, but shifted in the Y axis. So, first, is there a common shift between all of these lines? Or in other words, are the lines shifted by a constant value? Unfortunately, it appears that this isn't the case. The top line of Guybrush's speech is 1 pixel too far to the right and 7 pixels too far towards the bottom of the screen, while the bottom line is offset by 1 pixel to the right and 13 pixels too far towards the bottom of the screen. The text "Look at enemy pirate" is also offset by 14 pixels too high towards the top of the screen.

Let's look into the difference in line spacing between the two lines for Guybrush's speech. It turns out that in ResidualVM, the height of the font is modified when loaded if the character is taller than the specified font height. As before, this is intentional because of kerning. We do want some of the characters to sink lower or rise higher than the rest because it's pleasing to the eye. Simply commenting the section of code that modifies the height results in the correct behavior, so I looked up why that work around was inserted in the first place, which led to this commit. So, it appears that there was a crash bug associated with the height. I suspect that the problem would be fixed if the renderer uses the dataHeight instead of the height to draw the text.

As this blog post is getting long and I need to check with the other developers about this code, we'll wrap it up here for now. I'll continue in the next blog post with fixing the remaining font issues. All of the changes in this post can be found in PR #964.

by Joe Jezak (noreply@blogger.com) at July 15, 2014 04:42 PM

July 14, 2014

Stefano Musumeci (subr3v) - GSoC

2D Blitting API implementation explained.

In the past week I've been working on the implementation for the 2D blitting API for TinyGL.
As I've already explained and shown the design of the API I wanted to discuss its implementation in this blogpost.
At its core the API is implemented through a templated function called tglBlitGeneric:
This function chooses the best implementation based on its template parameters (everything is computed on compile time so this boils down to a simple function call), the current implementation supports different paths optimized for some cases:
  • tglBlitRLE
  • tglBlitSimple
  • tglBlitScale
  • tglBlitRotoScale

tglBlitRLE is an implementation that optimizes rendering by skipping transparent lines in the bitmap (those lines are loaded in advance when the blitting image is uploaded inside TinyGL through tglUploadBlitImage) and is usually selected when blending and sprite transforms are disabled.

tglBlitSimple is an implementation that cover a basic case where the sprite has to make use of pixel blending but is not transformed in any way (ie. not rotated or scaled) but it can be tinted or flipped either vertically, horizontally or both ways.

tglBlitScale is used when scaling is applied (plus whatever is needed between blending, tinting and flipping).

tglBlitRotoScale is used when all the extra features of blitting are needed: rotation, scaling plus blending/tinting/flipping.

After implementing the API I also had to replace the existing implementation in both engines: Grim and Myst3, the ending result is obviously the same but the code is now shared between the engines and any optimization will benefit both from now on.

This code will also be beneficial for the implementation of my next task: Dirty rectangle optimization that consists in preventing a redraw of the screen if the contents haven't changed, I will talk more about it and its design in my next blogpost this week.
Stay tuned!

by Subr3v (noreply@blogger.com) at July 14, 2014 07:39 PM

Joseph Jezak (JoseJX) - GSoC

Fixing the Position

Continued from the previous entry.

So now, let's return to position! First, let's examine the output of each of the actors for getpos(), getworldpos() and getrot() in the retail version of EMI, after running the rotation script:

actor1Output
getpos(1, 4, 5)
getworldpos(1, 4, 5)
getrot(5, 15, 25)
actor2Output
getpos(0.854459, -6.7806, -5.41233)
getworldpos(3, -1, -2)
getrot(3.98862, 13.1276, 7.01816)
actor3Output
getpos(-6.7911, 1.63313, -0.462462)
getworldpos(-3, -4, 2)
getrot(6.82211, -9.04857, -16.7055)

After a lot of debugging with IDA Pro, I discovered that the retail version actually maintains the computed or provided values for the Euler Angles, the same rotation as a Quaternion and a 3x3 Rotation Matrix. Additionally, it keeps the relative position (to the attached actor) and the world position. Instead of doing this in ResidualVM, these values are computed when needed.

It's important to note that there are functions in the retail version which keep these values synchronized, so the matrix, quaternion, or Euler Angle that you're inspecting might not be up to date. So, in the retail version, the status of each of the different rotation representations are stored in a bitfield which should be checked before assuming that a rotation value is correct. With those caveats, I then inspected the three actors' Quaternion and Matrix representations after attachment and compared them to the internal values in ResidualVM. For example, here is the 3x3 Rotation Matrix representation of the rotation of Actor 2 after attachment, taken from the retail version of EMI:

actor2: Retail Rotation Matrix
0.73705870.49632958-0.45869532
-0.472027960.863798320.17618749
0.483667310.0866464880.87095153

So, how did I fix the rotation? After each change to the rotation, I added breakpoints to check the Rotation Matrix value and changed ResidualVM to match these intermediate values. One major structural change that I made was to separate the generation of a rotation matrix from the generation of the final matrix (including the actor's position for translation). As these operations must be applied in the same order, it was better to do them separately.

Now, with a working rotation implementation, we can finally fix the position. As discussed before, getworldpos() should reflect the original location of the actor before attachment. To find the world position, we take the relative positions of each of the attached actors and combine them to find the actual position coordinates.

Finally, what are the position coordinates supposed to represent? It's the actor's relative position to the parent actor when attached, or the global position, when unattached. With correct rotation, the previous math that implemented the position actually matches with the retail version and no further work was required!

In addition to attaching, detaching doesn't work quite right in the current code either. When detached, in ResidualVM, an actor simply reverts to a rotation of (0,0,0) and doesn't have the correct position, instead of using the same position and rotation, but in a global basis. We can fix the rotation problem by simply getting the rotation quaternion for this actor, which already sums up all of the combined rotation of all of the actors and retrieving the Euler Angles from this quaternion. This fixes the problem and matches the retail version!

All of the the above changes can be found in the updated PR #948.

To test this implementation, klusark created a lua script that iterates over a bunch of angles and writes out the result to a file. I added the script to the local.m4b file and ran it on both the retail version and ResidualVM, then compared the two with another script that checks one against the other and ignores rounding errors. While there are some rounding differences, the output now appears to be correct!

So, in the end, after all of this work, does everything look correct? Was the location of the pole in mot fixed?

Nope, not rendering correctly still! And we broke the other actors!
Unfortunately, no. We still need to correct the rendering position of the actors now to match the changes that we made to the position and rotation of the actor. We'll tackle this in the next blog post.

by Joe Jezak (noreply@blogger.com) at July 14, 2014 12:11 PM

July 09, 2014

Lukasz Watka (lukaslw) - GSoC

First playable location

Hello everyone!

Quick update to show you my weekly progress. I was working on script part this week and I have some good news. ;)

After setting an interpreter's debugger, understanding of how game script is working was actually quite easy. Most of script functions are done and are working correctly now. It was about 60 functions to code. Many of them have just 10 - 20 lines of code, but they are doing huge job in the game (like setting frames of background animations and loading special animations).

Some of them was pretty complex though and needed serious thinking - like O_INITDIALOG.
I had to change the way text for dialog-boxes are stored. I was just using array of strings before, but it was to simple and it was blocking script. To fix it I had to stick with concept from original game that uses special characters, hidden inside texts, to know how whole conversation should look like (who is talking, where to make pause while talking etc).

After taking care of script I found lots of bugs. I had to update background animations to allow changing from one to another, make fix for some voice loading and change the way objects (like shovel) are set to visible. I also update some mouse button events again.

Right now I have first fully playable scene - graveyard and I looks so cool ;) I still have to fix map scene to allow to change to another locations correctly, but after some testing I think that basics of other locations should work well too. I have very slow Internet access where I live now, but I'll try to upload game-play of it later at night.

Location 1 - Graveyard
Gravedigger's magic

Location 1 - Graveyard
Summoning Arivald


I'm preparing for pathfinding part right now. I'd like to finish it this week. One of things that I'll have to take care next is saving. It should make testing easier and allow to skip beginning of the game.


by lukaslw (noreply@blogger.com) at July 09, 2014 04:18 PM

July 08, 2014

Peter Bozsó (uruk) - GSoC

Save and load system

Hi everybody! :)

My last week's progress is mainly centered around the save and load system. I had a couple of difficulties, but now CGE2 engine supports almost every Advanced Engine Features. I only left out "Return to Launcher" support, since the engine still have a lot of memory leak issues (even through I managed to solve a couple of them) needed to be fixed before that.


So as I said, now it's possible to load a gamestate via the launcher, or even do saving or loading in-game. I plan to also implement an autosave functionality, similar to the one implemented in CGE1, but for now it works and that's totally enough for debugging and the translation works of Arnaud.
I've got a couple of hardships during the implementation of this subsystem, but ScummVM's built-in Common::Serializer class helped me a lot and spared me a great deal of time by hiding the actual stream operations behind an abstract interface. Since the original game only supports saving when exiting the game, and loading when starting it, I had to make so modifications in the engine itself to make it possible to save/load anytime during gameplay. But knowing the internal workings of the engine, it was quite straightforward. The hardest part was to rework Spare and the way it's used, so now it's not just a temporary container for some of the sprites in the game, but a big catalog, which stores every Sprite used by the engine, all the time, so most of the synchronization work is to keep Spare up to date.

Otherwise, I mostly spent my time with annoying and hard to find bugfixes like this miracle.

During the past week, Arnaud went on a translation-frenzy. :D Thanks to him, almost all of the scenes of the game (Warning, spoiler alert!) are reachable/finishable. I just can't express my gratitude toward him. :)

My plans for the upcoming week is more bugfixes and even more taking care of various Valgrind errors, provided generously by David, what I am still really thankful for. :)

See you soon!

by uruk (noreply@blogger.com) at July 08, 2014 03:36 PM

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

July 03, 2014

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

Head tracking

For the past week I've been working on enabling head tracking. Head tracking allows actors to orient their head towards any point in the game world. This work is now included in PR #947.

The head tracking works by reorienting one of the bones of the skeleton after keyframe animation is applied. The bone is oriented to face the direction the actor wants to look towards. The look direction is interpolated, so the change in orientation is not instant.

The original Lua code uses the functions ActorSetHead and ActorSetHeadLimits to set up head tracking. The former takes as parameter the name of the bone that should be animated, while the latter takes three parameters that specify horizontal and vertical angle limits. The angle limits ensure that the head won't be oriented unrealistically.

My current implementation looks good in most cases, but I did find one case that looks noticeably different from the original. Mr. Cheese's head is at a weird angle when he looks towards Guybrush in the Scumm Bar. The screenshot on the left is ResidualVM, while the one on the right is the original.



The head tracking animates Mr. Cheese's neck bone, but the neck bone has children which are animated by keyframe animation, and the vertices of the head mesh follow the child bones. Although the neck bone is facing Guybrush, the head mesh is not, because of the animation applied to the child bones.

I spent a significant amount of time trying to figure out the difference between my implementation and the original during the week, but none of my solutions produced the same result as the original in this case.

One of my attempts was to override the animation of the neck bone as well as it's children bones completely whenever head tracking is active. This way the head was oriented exactly towards the point the actor looks at. That, however, didn't match the original game either. Mr. Cheese's head does seem to be affected by the animation also in the original.

For now I decided to leave this be. Mr. Cheese is currently the only case I'm aware of where the result is different from the original. I may return to this at a later stage once I've finished the other remaining tasks.

by Akz (noreply@blogger.com) at July 03, 2014 06:21 PM

July 01, 2014

Lukasz Watka (lukaslw) - GSoC

LMB outside of inventory, beginning of script part

Hello everyone!

Finally, my exam time is over and I move back from my student apartment in Gdansk to my hometown for next two months. Moving cost a lot of time and effort, but from now I'll have peace and quiet to do serious work with Prince's code ;)
I'm also waiting for results of two last exams and I wish I will pass all of them.

Let's talk about my progress in last days:

At the beginning of a week I was working on handling rest of LMB actions outside of inventory. I manged to finish rest of option frame events (Examine, Pick up, Use, Open/Push, Close/Pull, Talk to). I have to implement pathfinding part before finishing the last one - "Walk to".

After choosing one of these options, it searches in proper mobs/op codes list to check if any special event for selected mob exists. If it exists we store its op code as next for foreground interpreter. If not we just store standard procedure's op code. Something similar happens for "Give item" and "Use item" events outside of inventory (events with item taken out from inventory). Second important step it to set current mob flag to allow proper working of upcoming script's functions.

Next thing that I had to understand this week, was how actually the script part is working. I choosed "Examine" option for testing, set up interpreter's debugger to show only foreground op codes and start fixing my first script functions.

I was able to implement script O_GETMOBTEXT(), which also need big update in setVoice() function. It used to support only one type of voice file for intro part, now it should work for every voice in game.

Last thing that I fixed to finish "Examine" option was small, but was very hard to find out. I had to update loading data for longer texts, when prince is talking more then once, like for graves examining in first location. I also implement O_CHANGEMOB() that is used to set visibility of mob and allow to change from one mob to another, e.g changing "unknown grave" to "Arivald's grave" after first examining.

I also updated checkMob() function and it's displaying names of background animation mobs and objects now. I also checked original code and found part of code that update visibility of static mobs for each location.

Background animation - owl (left) / Object - shovel (right)
Displaying names of mobs


I was also trying to find memory leak problems and I fixed most of them, but part of implemented code still need some clean-up and tweaks.

Right now I'm working on dialog part in script for "Talk to" option. It should allow to get some serious progress and to actually play a game for a while, but it's pretty complex and it requires implementing about 4-5 new script functions, so stay tuned.

by lukaslw (noreply@blogger.com) at July 01, 2014 03:17 PM

June 30, 2014

Peter Bozsó (uruk) - GSoC

A bit of vacation and the Advanced Detector

Hey all! :)

During the last week, I spent a few days on vacation, so I haven't really progressed much with the engine. Truth to be told, I am still on time regarding my schedule, so everything is okay.
Besides that, Arnaud progressed a great deal with the translation, and with the implementation of a few more opcodes, we were able to unlock a couple of new scenes in the game. Here are some pictures of them:

Now, if I count it correctly, we have almost 10 playable scenes of the game, most of them fully translated. That's a quite good number if you take into account that the game has about 28 scenes in all. :)

Considering the advice of David (digitall), I also added a fallback detection for the English translation, so we don't have to modify gameDescriptions[] every time Aranud comes up with a new version of the translation.
In a nutshell, it's algorithm is very primitive: it checks for a "lang.eng" dummy file. If it finds it, the engine detects the game's data files as the WIP English translation. Of course, it's just a temporary solution, only used during the development. The cool thing is, it was VERY easy to implement, thanks to the great Advanced Detector what ScummVM provides. I only had to implement fallbackDetect(), and that's all, ScummVM takes care of everything else.

We also decided that the bug in the pathfinding can wait. It's absolutely not a showstopper, since you can interact with every sprite on the screen what needed to proceed with the game, it only blocks the player to wander around with our two heroes on certain screens. We postpone it for later, to be implemented with other rather "cosmetic" features.
This week, I am working on the save/load system, so we can test and translate the game much effectively and swiftly. Sadly, my parents are moving to a new house during these days, and I have to help them a lot, which consumes a lot of energy and time of mine. Nevertheless, I don't fear that will slow my progress significantly


Right after that, I'll have a pretty long list of Valgrind warnings to take care of as well. Great thanks again to David for providing me with these information, and helping me so much! :)

See you next time! (Hopefully with a working save/load system, and with much less memory leaks. :D)

by uruk (noreply@blogger.com) at June 30, 2014 01:06 PM

June 16, 2014

ScummVM News Headlines

Testing, Testing 1, 2, 3

The forthcoming 1.7.0 release of ScummVM is almost here! This time around, we have a total of five newly supported games:

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

But before we can release the latest and greatest version of ScummVM, we need help testing out all these new games. Besides the aforementioned new games for this release, the DOS floppy versions of Indiana Jones and the Last Crusade and Loom, require testing running with our AdLib emulator. You can always check out which games still need testing on our wiki. There are also a few other old classics on that list that could use another run through.

A daily build is all that is required to get started. If you happen to find any bugs, please report them on the bug tracker. After completing one of the games, please let us know on the forums so we can post the results up on the wiki page. Be sure to follow our guidelines for release testing, which can be found on the wiki as well.

And while you play through these newly supported games, please submit some screenshots!

by clone2727 (nospam@scummvm.org) at June 16, 2014 12:00 AM

June 07, 2014

ScummVM News Headlines

Release your inner Voyeur.

Or, the "Better late than never" announcement. It was pointed out to me today that although we merged Voyeur into the master branch some months ago, we never actually called for an official testing period. So this announcement seeks to remedy that.

Take on the role of a private investigator. A powerful CEO with aspirations for the presidency has invited his family to his home for the weekend. There are suspicions of corruption, and you've been hired to find out his secrets, and determine just what he's hiding.

The ScummVM Team is proud to announce that Voyeur is now playable in ScummVM using the latest daily builds, and ready for testing. As usual, all bugs should be reported to our bug tracker following our bug submission guidelines. While you play through the game, we would also love it if you could take some screenshots for us.

by DreamMaster (nospam@scummvm.org) at June 07, 2014 12:00 AM

May 27, 2014

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

Animation blending

In EMI, just like in many other 3D games the motion of a 3D model displayed on sceen may be a combination of several different keyframe animations playing simultaneously. For example, the animators may have supplied a 'walk' animation and a 'hold object' animation for a character in the game. The game engine may produce a 'walk while holding an object' animation by combining the lower body part of the 'walk' animation with the upper body part of the 'hold object' animation. This can be achieved with the animation priorities I described in the previous post. In addition, the engine can animate the transition between different animation states such as 'walk' and 'stand' by interpolating between them. This interpolation is what I refer to as animation blending.

With animation blending, the final animation that is displayed on the screen is the weighted sum of all simultaneously active animations. The weight of an animation (the "blend weight") determines how much contribution the animation has in the final result. The total sum of weights should equal 1. For example, we could animate the transition from 'stand' to 'walk', by linearly interpolating a value α from 0 to 1 over time and setting the blend weight of 'walk' to α and the blend weight of 'stand' to (1-α) at each step in time. The interpolated transition may not look completely realistic, but in most cases it looks much better than instantly snapping to another animation.

In EMI, the game may request certain animations to be faded in or faded out. To support this in ResidualVM, I store a 'fade' value for all active animations. When requested, the value is linearly interpolated between 0 and 1. If animations had equal priority, we could assign weight=fade for all animations and simply divide the intermediate weights by the total sum of weights to get the final normalized blend weights. However, with prioritized animations this changes a bit.

For higher priority animations we want to assign more weight than for lower priority animations. An animation with weight 100% will always completely override anything with a lower priority. If the animation has weight 60%, lower priority animations will only get to distribute the remaining 40% of weight among themselves.

How is this implemented? The way I'm doing it now is I first collect priority-specific accumulated contribution to animation "layers". Each animation layer contains the accumulated contribution of animation with a certain priority. For example, layer 0 contains the contribution of animation with priority 0, layer 1 contains the contribution of animation with priority 1, and so on. Within a layer we can assign weights for the animations in the simple fashion described before, with the exception that we'll only divide the weights by the total sum if the sum exceeds 1. I also assign a fade value to animation layers, which is simply the sum of weights.

Once the animation contribution is split into layers, we'll get the final result by blending the layers together. The blend weights are assigned so that the highest priority animation will contribute the most, and the remaining weight is distributed to lower priority animations. To be exact, the layer weights are calculated as follows for n layers:

weight_n = fade_n
weight_n-1 = fade_n-1 * (1 - fade_n)
weight_n-2 = fade_n-2 * (1 - fade_n-1) * (1 - fade_n)
...
weight_1 = fade_1 * (1 - fade_2) * ... * (1 - fade_n-1) * (1 - fade_n)

The end result is a system where each animation can be independently faded in and out, while still respecting animation priorities.

by Akz (noreply@blogger.com) at May 27, 2014 09:29 PM

 

curved edge   curved edge