Mar 16 2014

Fullscreen canvas, not as easy as it appears

Category: Software,WebdevelopmentSpiller @ 14:25

This is a rant about the erroneous information you will get when you try to find out how to implement something, you have been warned. See the end for the solution that was good enough for me.

I have been working on a WebGL based LDraw viewer, so I can embed 3D views of my Lego models on this blog (Project at Github: WebLDraw). Obviously I want to droll at them in glorious fullscreen, and with the HTML5 fullscren API it should be fairly simple. You just have to call ‘requestFullscreen()‘ on you element.

Well almost. In Firefox it applies 100% width and hight automatically, but not in Chrome, resulting in a small canvas on a large black background filling your entire screen. Awesome, uses your screen estate  as efficiently as Metro apps in Windows 8!

Applying a bit of CSS to do it manually should be fairly easy, but that just doesn’t work for a canvas, as it is rendered at a specific resolution, and the CSS style just upscales it. Googling for ‘canvas resize fullscreen’ will give you something like this:

function on_fullscreen_change() {
   canvas.width = window.innerWidth
   canvs.height = window.innerHeight
}
document.addEventListener( 'fullscreenchange', on_fullscreen_change() );

Great, now my canvas is bigger as soon as I enter fullscreen. And not only that, it is just as big as soon I exit fullscreen, because NO, do not exit the glorious fullscreen environment, it is perfect. So a bit more googling and I ended up using ‘document.fullscreenEnabled‘, which I quickly found out just told me if fullscreen was supported. The correct way was to do:

if( canvas == document.fullscreenElement )

Now I can finally enter and exit fullscreen properly. Except that my canvas did not have the correct size, ‘window.innerWidth’ does not give the correct width. But google have all the answers, you just need to do any of:

  • document.width
  • document.body.clientWidth
  • canvas.offsetWidth
  • canvas.getBoundingClientRect().width
  • canvas.style.width = window.innerWidth + “px” (CSS style, fancy)
  • screen.availWidth

None of them gives the correct result however. People don’t seem to notice because they stretch it with ‘width: 100%’ anyway. ‘screen.availWidth‘ exited me though, it actually returned 1920, the width of my screen. Except that ‘screen.availHeight‘ returned 1160 because YES, I do have a taskbar in my desktop environment, and NO, I don’t want to know it is 40px high when it is hidden anyway because I’m in fullscreen mode…

I really wonder why we need to differentiate between ‘screen.availWidth’ and ‘screen.width‘ which gives the screen’s full width in web development. Anyway, that was the final piece in the puzzle and my Dart implementation ended up looking like this: (Most of it maps pretty closely to a JavaScript implementation.)

original_width = canvas.width;
original_height = canvas.height;
canvas.onFullscreenChange.listen( (t){
  if( canvas == document.fullscreenElement ){
    canvas.width = window.screen.width;
    canvas.height = window.screen.height;
  }
  else{
    canvas.width = original_width;
    canvas.height = original_height;
  }
} );

Some of the confusion about the fullscreen API is hard to avoid, because many articles only applies to the old proprietary APIs. But 7 ways to get the monitor width, none of them which are correct? I just can’t even guess how it could end up that bad…

Tags:


Jul 21 2012

IE10 flip ahead and standards

Category: Software,WebdevelopmentSpiller @ 23:13

According to within windows IE10 has added a new feature to simplify page navigation. It is called “flip ahead” causes the browser to automatically find the next page if you click on the right side of the page. (It also makes a fancy slide animation which I guess tablet users will enjoy.) To quote within windows: “There are no futile attempts at tapping tiny links or looking for “next page” links on a badly designed website.”

There were two kind of responses in the comments, the ones praising the feature and the ones noting that this feature have been in Opera for years. As a avid Opera user I of course know about this feature and have been using it for a long time. (The main difference is that Opera doesn’t do the fancy animation and have like 10 different ways of activating it.)

But I’m not trying to be a Opera fanboy and rant about IE copying this feature. Rather, I’m happy that they do and hopefully the other browsers will too. Because this is an awesome feature, well, when it works. Sometimes the page you end up on can be completely unexpected.  And that is the issue, it isn’t really that reliable, and it is not really that strange when you consider the implementation.

The way Opera implements it (and most likely also IE) is, according to users on the web, by using a list of words which are likely to be in links pointing to the next page (in several languages). So if it finds a link which matches one of those entries, it will use that as the next page.

So this works when the page uses something commonly like “next page”. However one specific site might use “more destruction” instead of “next”. Will it work now? Perhaps, but in that case, what if another site didn’t have more than one page but did have a link to a site called “More destruction”. You could end up on a completely unrelated site or page. Such cases could be fixed, but there will always be some other special case.

So as a webdeveloper you will either have to carefully test the site in IE (and risking different behavior in Opera), or wait for some way or standard to specify the next page with some form for meta-data. Within windows says to lurk on the IE blog for tips on tailoring your site to this feature, however there is no need to wait on the bloging about it because there already is a way to specify this. Actually, it have been there for about 15 years, it is a part of the HTML 4 specification. It is a single element placed in the HEAD: [Document relationships: the LINK element]

<LINK rel="Next" href="Chapter3.html">

Lets quote the spec: “Next Refers to the next document in a linear sequence of documents. User agents may choose to preload the “next” document, to reduce the perceived load time.” Seems like it took the IE guys 15 years to notice this…

So why do browsers guess? Because way to many sites does not provide this information. And worse yet, a lot of people got it wrong, so several aliases was added to the HTML5 spec… (and I therefore recommend you to use the HTML5 spec as a reference to this instead.) Opera does support it, but because of the amount of websites that doesn’t provide it, the feature still seems shaky at best. Now when a bigger browser like IE gets support hopefully this will change, but it will still take time before the majority of websites adds it. And the “poorly designed” websites Within windows mentioned might never do it…

To conclude this rambling: It (again) saddens me to see the state of the web today.

EDIT: seems like MS really wants to try the impossible and get it working on all sites, just hear this: “Using Flip Ahead requires end user opt-in, and sends your browsing history to Microsoft to improve the quality of the experience.” [Web browsing in Windows 8 Release Preview with IE10]


Jun 23 2012

Image comparison with CSS

Category: Software,WebdevelopmentSpiller @ 16:07

As I’m browsing the web I sometimes tend to look at the source of the webpages and if it is questionable I consider how this could be improved. However at times it is just to painful to watch…

This website was reviewing Blue-Ray releases of TV broadcasts and showed the differences by overlaying screenshots from the TV and BD versions. When you hovered over them with the mouse, the image switched. This was implemented like this:

<style>
  .himage
  {
    -webkit-transition: opacity .4s ease-in-out 0s;
    -moz-transition: opacity .4s ease-in-out 0s;
    -o-transition: opacity .4s ease-in-out 0s;
    transition: opacity .4s ease-in-out 0s;
  }
</style>
<div style="position:relative;">
  <img src="http://i.minus.com/j5BVlrAz0767W.jpg" width="640" height="360" />
  <img class="himage" src="http://i.minus.com/j0KF3taUebpkC.jpg"
      width="640" height="360" onmouseover="this.style.opacity=0;"
      onmouseout="this.style.opacity=1;" style="position:absolute; top:0; left:0;"
    />
</div>

Instead of having the CSS in the style sheet as it should, it is unneeded repeated like this for every image. It also uses the style attribute on the elements which is also considered bad practice. (XHTML 1.1 actually deprecated it, but nobody uses that anyway…) I don’t see why you would use JavaScript here either when it is just a simple hover effect.

The HTML can be much simpler:

<div class="himage">
  <img src="http://i.minus.com/j0KF3taUebpkC.jpg">
  <img src="http://i.minus.com/j5BVlrAz0767W.jpg">
</div>

As you can see, the only requirements to do this in CSS is a container and a way to identify this container, here done with a class. The CSS is much the same, just not done as attributes:

.himage{ position: relative; }
.himage img{
  -webkit-transition: opacity .4s ease-in-out 0s;
  -moz-transition: opacity .4s ease-in-out 0s;
  -o-transition: opacity .4s ease-in-out 0s;
  transition: opacity .4s ease-in-out 0s;

  opacity: 0;
  position:absolute; top:0; left:0;
  max-width:640px;
}
.himage img:first-child{
  opacity:1;
  position: relative;
}
.himage:hover img{ opacity:1; }

There are some differences however:

  • The JavaScript have been replaced with the :hover selector (which is the last line).
  • Instead of specifying a fixed width and height, max-width have been used. The browser automatically resizes it to keep aspect ratio. (which was slightly wrong btw…)
  • To keep the HTML as clean as possible, the :first-child selector was used to differentiate the first and second img element. :last-child would have made the CSS simpler, however it is not supported in older versions of IE.

Live versions

You can watch the two versions here:

Note: The CSS is included in the HTML for ease of distribution, it should of course be in the style sheet.

Edit: My version behaves a bit differently, the hover area is the whole div and not just the img, if you want the same effect change .himage:hover img to .himage img:hover.

Compatibility

I cannot currently test it in IE7 and IE8 (and I don’t care about IE6), however I think it should work if you take the following in account:

  • The :first-child selector is supported from IE7, but not on content which have been inserted with JavaScript.
  • opacity is not supported in IE5-8, you will have to use MS filters in addition to opacity to get it working there. It is two extra lines of CSS for each time opacity is used, see this article on how to do it: quirksmode.org: opacity – IE compatibility note
  • The CSS3 transitions effects degrade gracefully. IE support will be in IE10, prefix not necessary (source).


Nov 30 2011

Color-independent CSS with alpha overlays

Category: Software,WebdevelopmentSpiller @ 00:07

This sidebar design caught my eye:

There are several of these boxes in different colors and I kinda liked the effect. To create this effect two images are used, one which contains the top part of the box, including the rounded corners and another which just contains the rounded corners for the bottom. (These needs to be separated so that the box can grow.)

However for each color there are a separate set of images and you have to set the color in the CSS too. This requires you to download several almost identical images to view the page which is not optimal. Secondly, in the case you want to change the color, you need to create a new set of images and then find the part in the CSS and change that too. If you wanted to mirror the boxes or change the design a little bit, you would have to redo every image, which again is not optimal.

So the optimal solution would be that the implementation didn’t rely on a specific color and that we could just change the color in the CSS and expect everything to work as intended. And this is indeed possible in this case. We can even use CSS3 transformation to change the color on-the-fly!

Color independent implementation

The trick here is to use alpha compositing to create the effect. If we placed a completely white image on top of the orange color, we would obviously end up with an completely white result. However what if the image had been 50% transparent? Then we would have ended up with a lighter orange color since some of it had been replaced with white.

This is exactly the effect we are going to exploit here. With image formats like PNG you can control the alpha (transparency) of each pixel by drawing on the alpha channel. So we will make a completely white image and then draw the two circles on the alpha channel. Let’s start with looking on the original image:

Notice that it is saved in JPEG and weights 7.18 KB. As explained previously, this should have been saved in PNG as it compresses better. So I remade it from scratch, trying to match the original image.

Here is the image, where we have drawn on the alpha channel instead:

(I had to make it blue as otherwise it wouldn’t have been visible as this blog´s background is white.)

Since this image is completely the same color, just with alternating alpha values, it will work nicely with all backgrounds. Try it out on different backgrounds and see the effect! And take a look at the file size too, it is only 1.82 KB, quite a bit less than the original. (The white version was 1.85 KB)

Using CSS3, we can create our box as easily as this:

width: 223px:
min-height: 140px;
border-radius: 5px;
background-color:  #f07575; /* Some random color here */
background-image:
   background-image: url('overlay.png'),
   -o-linear-gradient( top, rgba(0,0,0,0) 140px, rgba(255,255,255,0.41) 140px);
background-repeat:no-repeat;

First we set the width and the minimal height (so that it can expand), nothing special here. Next up is creating the rounded corners and setting the background color we want.

The background-image is the interesting part. First we use the overlay image we just made for this. We have background-repeat set to no-repeat, so it only appears where we want it.

Then a gradient suddenly appear? This is to make it look as intended when the box becomes larger than the 140px the image is. If we didn’t do anything, this would happen:

So to avoid this we could make our overlay image as long as the box possible could be, for example 1024 pixels high. This would increase the file size a little (to 2.97 KB) so let’s use CSS3 to do it in a more fancy way.

Instead of using a single image, we could use two, our normal overlay and a second overlay 1024 pixels high which is fully transparent the first 140 pixels and then becomes our semi-transparent white colors afterwards that. If we place those two on top of each other (using CSS3 multiple backgrounds) we can replicate the combined image.

Why do this? Because we can make our browser generate the second image by exploiting linear-gradients. Linear gradients are pretty flexible, we can specify several color-stops and the positions those stops should be at. So lets take a look at that piece of CSS again:

-o-linear-gradient( top, rgba(0,0,0,0) 140px, rgba(255,255,255,0.41) 140px);

We start at the top with a fully transparent black which should continue to 140px. Then we change the color to a transparent white, which should start at 140px. Our two colors start and stop at the same place, so we are actually not getting a gradient as the switch is instantaneously. However what we do get is the image we want, and it will automatically expand to even more than 1024 pixel if required.

The sample page ends up looking like this:

CSS2 implementation

The only part I will cover here is how to make the rounded corners color-independent. Download the sample page to see the full implementation.

Adding rounded corners so they don’t depend on the color of the box is pretty simple, just draw the inverted corner so that you draw the page background. This will of cause make it dependent on the background of the page, but it is better than it being dependent on both, right?

(Again in blue because of the blog theme.)

Sample page download

You can download the images and HTML+CSS2/3 source here: http://www.box.com/s/rgslnmrbtaqaeyppbly8

The file css2.html contains the CSS2 implementation and the file css3.html contains the CSS3 implementation. The CSS3 implementation also contains a little extra stuff to make it fall-back more gracefully.

Tags:


Nov 20 2011

Saving images in the correct format

Category: Software,WebdevelopmentSpiller @ 00:32

I quite often see images stored in wrong formats, see for example this website: http://www.retrofit-anime.com/index.html.

Notice the gradient, it contains ugly lines moving from top to bottom. (More visible on a dark background.) It was properly saved as a 1px high image and then stretched downwards (in order to make the file smaller), however it was saved as JPEG. There are two issues here. First of all, the compression artifacts becomes quite clear as they are repeated, however gradients like this also compresses better in a lossless format like PNG, so it is actually larger than it could have been, with worse quality.

So here is a introduction to image formats which will hopefully give you an idea of when to use one format instead of another.

Compression

File formats uses one of 3 types of compression:

  • No compression: The file is simply raw data and can be read and modified directly. The files usually ends up being rather large though.
  • Lossless compression: The format saves the data in a way that makes the data fill less on the disc, however it still contains all the data. (Like a .zip archive.)
  • Lossy compression: Saves the data, but trows away some of it in a way that the user (hopefully) wouldn’t notice.

Each type has its pros and cons. (Examples are all non-image formats.)

Not compressing at all makes it very fast to display the image when you can access the data just as fast. This is usually the case with an HDD as its reading speed is up to 100 MiB/s (and with SSD reaching speeds of 300MiB/s), however not on the web as the speed is rather slow, often something like 0.5MiB/s (which is 4Mb/s). However its simplicity is its main strength and most file formats (.txt, .exe, .doc, .html, .css, .tar and so on) are therefore uncompressed.

Lossless compression reduces file size greatly in most cases and is therefore used when file size is of importance. The downside is that it becomes slower to open and save, as it has to decompress and compress the file each time. It is also a lot harder to implement. Examples are .docx, .zip and .flac.

Lossy compression reaches file sizes which are normally much smaller than possible with lossless compression, however in the process some data is lost and is impossible to recover. While this might sound terrible, the low file size sometimes is worth the trade-off. Lossy compression usually try to trow away the data humans wouldn’t notice (so much) to avoid losing ‘important’ data. Formats which use this kind of compression is normally media formats (like sound, images and movies) as this kind of data usually is rather large. Examples are .mp3 and .h264.

Image format types

There are two different kind of ways to store an image, Raster and Vector. Raster describes a 2D grid of pixels, just like how your monitor displays it. All popular formats are Raster, that is JPEG, PNG and so on. Vector describes how drawing functions should draw on this 2D grid in order to create an image, for example: ‘draw a line from (30,40) to (100,50) and then draw a circle in (50,50) with radius 10’. Examples on vector formats are SVG and Lego Mindstorms RIC.

Since Vector images are something you create from the bottom up, focus in this post will be on the Raster formats.

Colors in images

The more colors you have to represent in an image, the larger the file becomes. So there are several ways of storing colors and switching from one to another greatly affects size. There are three important modes: indexed, grayscale and truecolor.

Truecolor

This is the normal model which contains all the colors you can display on your monitor. This is normally stored as RGB, i.e. three colors.

Grayscale

Grayscale contains only shades of gray and is stored with a single color. This makes it much smaller than Truecolor, however only in grayscale.

Indexed

Indexed is a bit different. Instead of storing a color for each pixel, it stores an index. This index then refers to a color table which contains a list of truecolors. This means it can only store a few colors (usually up to 256), but you can usually get good results anyway with dithering. Some images, like screenshots might only contain a certain subset of colors which can be indexed, reducing the size greatly sometimes without any loss.

Notice however that this index also takes up a bit of space and if your image contains less than 256 pixels, you might be better of staying in Truecolor.

Alpha

This is a special color, which can be used in addition to Truecolor, Grayscale or Indexed. Alpha specifies the transparency of an pixel which can be quite useful when combining several images together.

However in most situations it is not needed, so make sure you don’t save the alpha values in those cases.

Size of colors

In truecolor and grayscale you store levels of certain colors, like Red, Green and Blue for RGB. However the amount of different shades of the color affect file size too.

A color is usually stored as 8-bit which equals to 1 byte, meaning that it can contain 2^8 = 256 shades of that color. Grayscale uses one color, which means one byte per pixel, while Truecolor uses 3 colors, so it uses 3 bytes per color. If there is an alpha color for each pixel, it would use 1 byte more, to a total of 4 bytes per pixel.

Indexed images with a color table of 256 colors would need to store 8 bits per pixel, as 2^8 = 256. However if your color table is 250 you do still need to store 8 bits, since 7 bits only gives 2^7 = 128. So there is not as much advantage going saving a few colors, unless it will reduce the amount of bits needed per pixel. (The color table will of course be smaller though.)

As said, a color is usually sized to 8-bit, however some images might store more than that per color. 16-bit per color is often used with photography as the more levels increases accuracy when editing the images. However this also means that it uses up twice as much space per pixel, 48-bits, and you can’t display this on monitors either as most are 24-bits (or 18-bits for cheap screens). If you don’t need this, converting to 8-bit can significantly reduce file size.

Overview of image formats

Here is a table over the most common image formats (and I added Lego RIC just for fun).

The most important are PNG (lossless) and JPEG (lossy) as most of the others either compresses badly or is relatively unsupported.

The uncompressed formats like .png and .bmp should be avoided unless you have a good reason to use it, PNG provides just as good result at smaller file size.

TIFF is a bit of a joker, it has many features, however only some are implemented in certain applications. Only use it if you know what you are doing.

JPEG2000, JPEG XR and WebP are some of the popular formats for the future, however both are poorly supported at the moment.

GIF still rule animated images, however there are three alternatives out there, APNG, MNG and WebP.

Guidelines:

Saving while working with images (working copy)

Always use the applications native format if you intend to continue working with the image. This is the only way to ensure that as most data as possible is saved. Most formats doesn’t support layers or any other advanced feature your image editor supports, so all this information will get lost.

If you must save it in a genetic image format, use a lossless one like PNG. (TIFF might save more depending on the implementation, experiment!) If  you save it in a lossy format like JPEG, you will degrade image quality each time you save (and then open it again), as it each time trows a different set of information out.

Lossless versus lossy

In general I tend to use lossless whenever file size is not of great concern. HDDs have reached sizes of 3TB, the only thing not worth saving in lossless today is movies.

But lossless does compress better than lossy in some cases. JPEG works great for  photographs and can easily half the file size compared to PNG. However if the images are more simple graphics, like vector graphics or screenshots of your desktop, PNG suddenly compresses much better. Secondly, the JPEG compression artifacts ruins text readability, so PNG is a much better choice here.

To give you an example, here are two separate screenshots of my two monitors.

Example of good PNG compression

The left monitor, the PNG is 448KB and the JPEG became 777KB at acceptable quality. Try to convert the PNG I supplied and see the difference in quality for yourself.

Example of poor PNG compression

On the right monitor a large amount of my wallpaper was visible. Now the PNG suddenly became 1.95 MB while the JPEG was 801KB. (I have only supplied the JPEG here.)

So as you can see, compression depends a lot on the image. For photos use JPEG. For screenshots, your pie-charts and other similar images, use PNG. For images somewhere in between those, try saving in both PNG and JPEG and compare the sizes and quality.

Don’t convert a lossy image

I have seen it a couple times now, a JPEG image converted to PNG for absolutely no reason. The image will not magically get better by converting it to a lossless format! And even in cases where a lossless normally would compress better, it will not because the JPEG compression added artifacts which the lossless compression conserves. The first test image above became 1.5MB instead of 448KB when converting it to JPEG and back.

Trying to convert a lossy to another lossy format will only mean that you loose even more information in the image, so this is not desirable either.

So it is best to keep the lossy file as it is if you are not going to edit on it.

GIF versus PNG

If you try to save an image in both GIF and PNG, PNG might end up being quite a bit larger. However that is because GIF only supports indexed mode and that it is therefore automatically saved like this, while the PNG is saved in truecolor.

If you save PNG is indexed mode, PNG will in almost every case be smaller than GIF. So there is no reason to use GIF, as PNG compresses better and have more features (except animation).

If you are a web-developer, PNG with alpha works in IE7 and up, while PNG in indexed mode should work in IE6 AFAIK. So you should be able to replace GIFs with PNGs here too.

Index colors when possible

Indexing the colors can reduce the size quite a bit. With diagrams and the like you might not use the 256 colors up at all, so you can sometimes do this conversion without loss or with minimal changes. (In those cases you can dither the image to get prettier results, but it will hurt compression ratio. I would recommend to avoid it…)

The file comparison table a few sections above is an indexed PNG, and no colors were reduced as it only contained 140 different colors from the start. The size in truecolor is 22.5 KB, and when indexed it is 9.79 KB. (In JPEG it became ~125 KB…)

Don’t save transparent pixels

If you have some parts of the image fully transparent, the pixels color will still be saved even though it will not be displayed. This way, when you change the alpha, the original color will remain.

However if you do not need to do this anymore, you can change all completely transparent pixels to the same color. While it will not change the image’s appearance, it will reduce the file size. (Your image editor might have an option to do this for you.)

Animation

GIF is still the main format for animations around, and while it only works for indexed images, there are no real alternatives out there which have good application support.

There are currently three formats other than GIF which supports animation, APNG, MNG and WebP.

APNG is a modification of PNG which adds animation, however the issue with this format is that it uses same mime-type as PNG and thus can’t be differentiated. PNG directly disallows multiple images, so they are two different formats. However it is implemented in Firefox (the creators) and Opera.

MNG is also based on PNG, however it is a separate format. It is quite advanced and offer many possibilities than APNG does not, however its complexity is what has caused it to have nearly nonexistent support. (GIMP support, however animation support in GIMP isn’t that great anyway…)

WebP have recently announced animation support (which works similarly as GIF), and as it supports both lossless, lossy and alpha, it sounds promising. While WebP is implemented in Google Chrome (the creators) and Opera, I do not know whether animation have been added yet.

The future

Both JPEG and PNG is fairly old, PNG is from 1996 and JPEG 1992. Compared to how audio and video formats have evolved the past 10 years, images formats are still stuck in the past. I suspect that you could just replace the default compression algorithm in PNG with something like LZMA and get a 10-20% improvement…

JPEG2000 by the JPEG group was a new format which intended to replace the JPEG format. However support have not been very widespread even though the format was publicized 10 years ago. It is getting better by now though.

There are other similar formats, like JPEG XR by Microsoft, however it does not have good support either. WebP is the newest of the bunch which was publicized 1 year ago, however support is increasing and since it is based on WebM, good browser support is likely and it is already natively implemented in Chrome and Opera (and should be working in any WebM compatible browser via a JavaScript shim).

Which format that is going to get widespread is hard to tell. WebP seems to have a better chance on the Web, however I suspect that it doesn’t have as many advanced features as JPEG2000 and JPEG XR which especially photographers wants.

My guess however is that the Web is the most crucial factor, as this is where lossy compression is most important. I still however have my doubts with WebP in professional photography.

Tags: , , , , , , ,


Feb 18 2010

Rewrite of XML -> HTML conversion

Category: NXT RPG,WebdevelopmentSpiller @ 18:43

As I said previously, this process wasn’t very efficient. So I rewrote large parts of the code for the conversion of NXT RPG XML data files.

File system

All files have so far been placed in the same folder. So I decided to organize it a bit:

  • [folder] “global” : Contains all XML files that is used throughout the game
  • [folder] “graphics” : Contains all graphics used in the game
  • [folder] “levels” : Contains all levels used in the game
  • [folder] “shared” : Contains all XSLT files used for previewing/converting files
  • [folder] “strings” : Contains all strings used in the game
  • fileindex.xml : Contains a list over all game files

fileindex.xml

I wanted it to be possible to choose your own names, so “level42.xml” could instead be “Scary shopping mall.xml”. So fileindex.xml contains these names. It looks like this:
<files>
<global>
<gamestart>gamestart.xml</gamestart>
<gamedata>Gamedata.xml</gamedata>
<character_list>character list.xml</character_list>
<attack_list>attack list.xml</attack_list>
</global><levels>
<level id="1">lvl_1.xml</level>
<level id="2">lvl_2.xml</level>
<level id="3">lvl_3.xml</level>
</levels><graphics>
<sprite id="1">bg1.xml</sprite>
<sprite id="2">bg2.xml</sprite>
<characters>characters.xml</characters>
</graphics><strings>
<string id="1">strings_1.xml</string>
</strings>
</files>

It should be rather straight forward.

<global>

  • <gamestart> Filename of the file containing information needed for starting a new game.
  • <gamedata> Filename of the file containing information about the game, the name of the game and such.
  • <character_list> Filename of the file containing a list over all characters available in the game.
  • <attack_list> Filename of the file containing a list over all attacks available in the the game.

<levels>

  • <level id=”x”> Filename of the file containing the level data. “x” is a number from 1 to 254 which is used to identify the level.

<graphics>

  • <sprite id=”x”> Filename of the file containing information about the graphics used for level maps. “x” is a number from 1 to 254 which is used to identify the graphic sprites.
  • <characters> Filename of the file containing information about the graphics used for characters.

<strings>

  • <string id=”x” > Filename of the file containing a list of strings. “x” is a number from 1 to 254 which is used to identify the string list.

Issue in Firefox

This just doesn’t work that well in Firefox. Style sheets  accessed by “../” are blocked so basically nothing shows up if you try to open it. There is more about it here.

You can work abound the issue by opening “about:config” and change “security.fileuri.strict_origin_policy” to false. I don’t like it, but I’m not using Firefox so I’m not going to use time on it. However if any knows about a fix where it isn’t needed to move the files, inform me about it and I might fix it.

    Graphic files

    This needed to be a bit more organized. Up to now I had created a folder which was called the same as the ID for the level sprites (so something like “1”, “2” and so on…). Inside that folder was a image for each sprite, so quite a bit…

    In NXT RPG however the graphics are stored in one .RIC file. So I wanted to do the same here so the file looks like this:

    The sprites used for ID1

    Together with the image there is a XML file like this:

    <graphic>
    <filename>Lv1_bg.png</filename><type>bg</type>
    <id>1</id>

    <sprites>30</sprites>
    <size_x>10</size_x>
    </graphic>

    <graphic>

    • <filename> The filename of the image containing the graphic.
    • <type> The type of graphics. This can contain one of two values. “bg” is used for level sprites and “characters” is used for character sprites.
    • <id> The ID of “bg” graphics. If <type> is “characters” this value must be “0”.
    • <sprites> The amount of sprites contained in the image.
    • <size_x> The size of each sprite in pixels. All sprites are quadratic at this point.

    Implementation in HTML and CSS

    An empty <div> is given a class called “[type][id]_[number]” where “[type]” is <type> (“bg” or “characters”), [id] is <id> and “[number]” is the sprite you want. An example could be “bg1_4” if you want the sign sprite in the image above.

    The CSS is created dynamically and looks like this:

    [class*="bg1_"]{
    height:10px;
    width:10px;
    background-image:url('../graphics/Lv1_bg.png');
    }

    .bg1_4{
    background-position: -40px 0px;
    }
    A “.bg1_x” selector is created for each value of “x”

    Level files

    Those were main reason for rewriting it all. In Opera 10.50 beta it got corrupted if the HTML file became too large. Well, it really was large from the start, but most of it was just level previews that where repeated. So I wanted to remove those of course. (It didn’t work properly in IE either, but who cares…)

    I don’t fell like writing more right now, so I will make it short.

    Every level in fileindex.xml is created and assigned a (html) id based on the level (XML) ID. Then some CSS is assigned dynamically to connect the Events with the correct level preview. I will update this part later…

    Last heading

    There is still a few things to get done, but most of the functionality is already done.

    Any suggestions are welcomed.


    Feb 13 2010

    Using :before/:after for extra background-images

    Category: NXT RPG,WebdevelopmentSpiller @ 00:32

    First a small introduction you might just as well skip… (actually, just scroll down to the bottom…=

    Level files used in NXT RPG are saved in binary of space reason, but this of course is hard to manually create and maintain and very much error prone. So I created my own tools using XML, XSLT, and made a small application to convert values to NXT binary values.

    It is pretty simple, the XML file stores data about the level, the XSLT file then creates a visual aid so it is easy to see what is wrong and a text code. The text code is then converted to binary by the application I wrote.

    End of story.

    The issue

    The XSLT file I made works, but it isn’t that efficient. The level is shown using X*Y images (which is often around 200); this really can’t be avoided. However I also include a small preview of the levels it is linked to, which adds another 200 per level. However I might need the preview in 2 places or more, but right now they aren’t reused. Because of this, the total amount of img elements normally adds up to 2000-4000. Ugh…

    Optimizing: Small steps first

    The level is viewed in two modes: normal and solid. Normal will show the level map as it looks like in the game, solid will show an overlay which tells which blocks on the map are, well, solid.

    This overlay is created by adding another X*Y images, where the overlay graphic are loaded on some elements. Not  that efficient…

    The solution became to use :before in CSS to add a absolutely positioned block inside the <img> which contain the overlay graphic.

    I tried it, it worked fine in Opera and it simplified the XSLT and resulting HTML a bit. Then I opened it in FireFox and :before didn’t work. Same thing in IE8. After a bit of testing I discovered that :before doesn’t work on <img> elements. After changing it to <div> and background-image the problem disappeared.

    I’m not really sure what is correct, but Opera seems to allow generated content everywhere, you can even say “head{display:block;content:”yay”}” and the “yay” appears at the top of the page. So I guess it is Opera that is at fault…

    Going crazy

    Then I wondered, how many “overlays” could I create with this method? By using both “content:url(‘img.png’)” and “background-image” you would have two. Then you could also add :after to double this to 4. Alternatively you could also create an underlay by setting background-image on the <div>.

    To test it out I tried to create a box with rounded corners using only a single <div>.

    It is basically the same as previously, however :before and :after is set to display:block. It is just useful for this example since it makes the positioning quite a bit easier…

    Box with rounded corners

    This will not work in IE6/7, so the advantage of using this instead of border-radius might not be that big… Secondly, positioning the imaged specified by “content:” can be a bit more tricky if the element is flexible in size… But it might be interesting in other cases…

    The code is here, without the images though:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en">
    <head>
    <title>Title</title>
    <link rel="stylesheet" type="text/css" href="main.css"/>
    <style>
    .Rbox{
    width:25%;
    background-color:#6267ff;
    padding:0 10px;
    }
    .Rbox:before, .Rbox:after{
    display:block;
    height:10px;
    background-repeat:no-repeat;
    background-position:top right;
    line-height:0px; /* remove issue with whitespace... */
    margin:0 -10px;
    }
    .Rbox:before{
    content:url('lt.png');
    background-image:url('rt.png');
    }
    .Rbox:after{
    content:url('lb.png');
    background-image:url('rb.png');
    }
    </style>
    </head><body>
    <div>something... texty texty... texty texty... texty texty... texty texty... texty texty... texty texty... texty texty... </div>
    </body>
    </html> 

    Tags: