ScummVM logo Forum Index - ScummVM website - Contact us - Buy Supported Games: GOG.comDotEmu  Rules - Search - Register - Login curved edge
Folder Forum Index > The Junkyard > Possible support for "The Neverhood"? Goto page 1, 2, 3  Next
Possible support for "The Neverhood"?

"The Neverhood" for ScummVM?
Yes
82%
 82%  [ 32 ]
No
10%
 10%  [ 4 ]
Maybe
7%
 7%  [ 3 ]
Total Votes : 39

  Author    Thread Reply to topic
SonicTheBro



Joined: 23 Dec 2008
Posts: 1
Possible support for "The Neverhood"? 

Just wondering. Here are some pro's and con's:

Pros:
It's an adventure game
Sprite based (I think)

Cons:
Has Video
Has also been for Windows
Not really the same as a SCUMM game

There's probably more, but that's all I could think up.

 Reply with quote  
Post Tue Dec 23, 2008 4:17 pm 
 View user's profile Send private message
md5
ScummVM Developer


Joined: 03 Nov 2005
Posts: 2065
Location: Athens, Greece
 

http://www.scummvm.org/faq.php#id2503871

 Reply with quote  
Post Tue Dec 23, 2008 4:24 pm 
 View user's profile Send private message
clem



Joined: 31 Oct 2005
Posts: 2185
 

And forum rule 1a.

 Reply with quote  
Post Tue Dec 23, 2008 4:50 pm 
 View user's profile Send private message
iPwnzorz



Joined: 06 Jan 2007
Posts: 301
Location: Hampshire, England
 

But the description for The Junkyard...

 Reply with quote  
Post Tue Dec 23, 2008 5:08 pm 
 View user's profile Send private message
sev
ScummVM Lead


Joined: 21 Sep 2005
Posts: 1791
Re: Possible support for "The Neverhood"? 

quote:
Originally posted by SonicTheBro
Just wondering. Here are some pro's and con's:

Pros:
It's an adventure game
Sprite based (I think)


Wow! Finally there is someone who wants to develop an engine for Neverhood! Cool! I voted "yes"!!


Eugene
 Reply with quote  
Post Tue Dec 23, 2008 8:04 pm 
 View user's profile Send private message Visit poster's website
Longcat



Joined: 23 Sep 2006
Posts: 896
Re: Possible support for "The Neverhood"? 

quote:
Originally posted by sev
quote:
Originally posted by SonicTheBro
Just wondering. Here are some pro's and con's:

Pros:
It's an adventure game
Sprite based (I think)


Wow! Finally there is someone who wants to develop an engine for Neverhood! Cool! I voted "yes"!!


Eugene


Not sarcastic at all:P

I recently played The Neverhood actually, and incidently, it ran just fine in win xp. But portability sure would be nice:)
 Reply with quote  
Post Wed Dec 24, 2008 3:18 am 
 View user's profile Send private message
iPwnzorz



Joined: 06 Jan 2007
Posts: 301
Location: Hampshire, England
Re: Possible support for "The Neverhood"? 

quote:
Originally posted by sev
quote:
Originally posted by SonicTheBro
Just wondering. Here are some pro's and con's:

Pros:
It's an adventure game
Sprite based (I think)


Wow! Finally there is someone who wants to develop an engine for Neverhood! Cool! I voted "yes"!!


Eugene


Don't be like that. Isn't it easier to say "Sorry, but ..."

You know you don't have the FAQ very clear on the frontpage, it's one tiny little link hidden in the menu, so no surprise no one reads it.
 Reply with quote  
Post Wed Dec 24, 2008 10:01 am 
 View user's profile Send private message
noize



Joined: 31 Oct 2005
Posts: 113
Re: Possible support for "The Neverhood"? 

quote:
Originally posted by iPwnzorz
You know you don't have the FAQ very clear on the frontpage, it's one tiny little link hidden in the menu, so no surprise no one reads it.


Every forum subject has a sticky called "Forum rules". One of these rules is reading the faq before posting.

I also voted yes. Neverhood support would be great of course.
 Reply with quote  
Post Wed Dec 24, 2008 11:09 am 
 View user's profile Send private message
Onkel Hotte



Joined: 28 Aug 2009
Posts: 2
 

(Sorry for the thread necromancy.)
Cons:
- Doesn't seem to be script based, so would require the original source code or a re-implementation.
Having said that:

code:

import struct, array, wave, sys, os
from ctypes import *

# Enable headless pygame
 
# set SDL to use the dummy NULL video driver,
#   so it doesn't need a windowing system.
os.environ["SDL_VIDEODRIVER"] = "dummy"
 
if True:
    # Some platforms might need to init the display for some parts of pygame.
    import pygame.display
    pygame.display.init()
    screen = pygame.display.set_mode((1,1))

import pygame
from pygame.locals import *

# Some magic to make the blast decompression function available from inside python

class BUFFER(Structure):
    _fields_ = [("data", c_void_p), ("len", c_uint)]

# typedef unsigned (*blast_in)(void *how, unsigned char **buf);
BLASTINFUNC = CFUNCTYPE(c_uint, c_void_p, POINTER(c_void_p))

def py_blast_in_func(a, b):
    buf = cast(a, POINTER(BUFFER))
    b[0] = buf.contents.data
    return buf.contents.len

blast_in_func = BLASTINFUNC(py_blast_in_func)
   
# typedef int (*blast_out)(void *how, unsigned char *buf, unsigned len);
BLASTOUTFUNC = CFUNCTYPE(c_int, c_void_p, c_void_p, c_uint)

def py_blast_out_func(a, b, c):
    buf = cast(a, POINTER(BUFFER))
    memmove(buf.contents.data + buf.contents.len, b, c)
    buf.contents.len += c
    return 0
   
blast_out_func = BLASTOUTFUNC(py_blast_out_func)

if __name__ == "__main__":
    # make an output directory
    if not os.access("data", os.F_OK):
        os.mkdir("data")

    # You need to make a dynamic library of zlib/contrib/blast.c, on MacOS that is
    # gcc -dynamiclib -o blast.dylib -dylib blast.c

    lib_blast = CDLL("blast.dylib")
    blast = lib_blast.blast
    blast.restype = c_int
    blast.argtypes = [BLASTINFUNC, c_void_p, BLASTOUTFUNC, c_void_p]

    f = open("nevdemo_full/NEVDEMO.BLB", "rb")
   
    # Header
    (magic, id, unknown, dataSize, fileSize, file_number) = struct.unpack('<4sBBHLL', f.read(16))
   
    if magic != "\x40\x49\x00\x02":
        print "wrong id, not a blb file"
        exit()
   
    # file ID
    id_table = []
    for i in xrange(file_number):
        (id,) = struct.unpack('<L', f.read(4))
        id_table.append(id)
   
    # dir entries
    file_table = []
    for i in xrange(file_number):
        file_entry = struct.unpack('<BBHLLLL', f.read(20))
        file_table.append(file_entry)

    # offset shift table (for music and sfx files)
    shift_table = f.read(dataSize)

    # initial pal
    pal = [(x,x,x) for x in xrange(256)]
   
    # export files into raw
    file_type = { 7: "sound", 8: "music", 10: "video", 2:"image", 4:"animation" }
    file_ext = { 7: "wav", 8: "wav", 10: "smk", 2:"tga", 4:"tga" }
    for i in xrange(file_number):
        (type, mode, index, id, start, in_len, out_len) = file_table[i]
        if mode != 101:
            f.seek(start)
           
            data = f.read(in_len)
            if mode == 3:
                buffer = create_string_buffer(out_len)
                in_buf = BUFFER(cast(data, c_void_p), in_len)
                out_buf = BUFFER(cast(buffer, c_void_p), 0)
                blast(blast_in_func, byref(in_buf), blast_out_func, byref(out_buf))           
           
                data = string_at(buffer, out_len)
           
            if type in [7,8]:
                # sound/music
                if index > len(shift_table):
                    shift = 255
                else:
                    shift = ord(shift_table[index])
           
                w = wave.open("data/%s-%i.%s" % (file_type[type], i, file_ext[type]), "wb")
                w.setnchannels( 1 )
                w.setsampwidth( 2 )
                w.setframerate( 22050 )
               
                if shift < 16:
                    buffer = array.array( "h" )

                    curValue = 0
                    for val in data:
                        val = (ord(val) ^ 128) - 128
                        curValue += val
                        try:
                            buffer.append(curValue << shift)
                        except OverflowError:
                            try:
                                # This obviously means that something is going wrong with the decompression or with the scaling
                                buffer.append(curValue)
                            except OverflowError:
                                buffer.append(0)

                    # I'm not sure if this is required, it doesn't seem to be on MacOS. Maybe WAV does the endian-swap internally, or stores a flag in the wav header?
                    if sys.byteorder == "little":
                        buffer.byteswap()
                    w.writeframes( buffer.tostring() )
                    del buffer
                else:
                    if (len(data) & 1) != 0:
                        data = data + "\0"
                    w.writeframes( data )
                w.close()

            elif type == 2:
                #  image
                (format, width, height) = struct.unpack('<HHH', data[0:6])

                # Format flags
                # 0x1 - compressed
                # 0x4 - offset
                # 0x8 - palette

                pos = 6
                if format & 0x8:
                    pal = [(ord(x[0]), ord(x[1]), ord(x[2])) for x in [data[pos + idx * 4: pos + 3 + idx * 4] for idx in xrange(256)]]
                    pos += 1024
                    # I assume the palette is decided by the room an item appears in. But reusing the last palette makes things at least visible
               
                if format & 0x4:
                    # some kind of position?
                    offset = struct.unpack('<HH', data[pos:pos+4])
                    # print offset
                    pos += 4

                if format & 0x1:
                    # compressed
                    framebuffer = array.array("B")
                    framebuffer.extend([0 for x in xrange(width * height)])
                    ypos = 0
                    while True:
                        header = struct.unpack('<HH', data[pos:pos+4])
                        pos += 4
                        if header == (0,0):
                            break
                        (row_count, items_per_row_count) = header
                        for row_index in xrange(row_count):
                            for item_index in xrange(items_per_row_count):
                                (xpos, ) = struct.unpack('<H', data[pos:pos+2])
                                pos += 2
                                (fragment_len,) = struct.unpack('<H', data[pos:pos+2])
                                pos += 2
                                for b in xrange(fragment_len):
                                    framebuffer[ypos + xpos + b] = ord(data[pos + b])
                                pos += fragment_len
                            ypos += width
                           
                    surface = pygame.image.fromstring(framebuffer.tostring(), (width, height), "P")
                    surface.set_palette(pal)
                    pygame.image.save(surface, "data/%s-%i.%s" % (file_type[type], i, file_ext[type]))
                    del framebuffer
                else:
                    # uncompressed
                    surface = pygame.image.fromstring(data[pos:pos + width * height], (width, height), "P")
                    surface.set_palette(pal)
                    pygame.image.save(surface, "data/%s-%i.%s" % (file_type[type], i, file_ext[type]))

            elif type == 4:
                header = struct.unpack('<HHIIII', data[0:20])
                # print "%x" % i, header

                palette_offset = header[3]
                pal = [(ord(x[0]), ord(x[1]), ord(x[2])) for x in [data[palette_offset + idx * 4: palette_offset + 3 + idx * 4] for idx in xrange(256)]]
               
                pos = 20
                if header[0] == 2:
                    unknown_header = struct.unpack('<HHHH', data[pos:pos+8])
                    # print unknown_header
                    pos += 8
           
                frame_count = header[5]
                frame_list = []
                for frame_index in xrange(frame_count):
                    frame = struct.unpack('<hhhhhhhhhhhhhhI', data[pos + frame_index * 32:pos + 32 + frame_index * 32])
                    # print frame
                    frame_list.append(frame)

                data_offset = header[2]
                for frame_index in xrange(frame_count):
                    frame = frame_list[frame_index]
                    width = frame[5]
                    height = frame[6]
                    pos = data_offset + frame[14]

                    framebuffer = array.array("B")
                    framebuffer.extend([0 for x in xrange(width * height)])
                    ypos = 0
                    while True:
                        header = struct.unpack('<HH', data[pos:pos+4])
                        pos += 4
                        if header == (0,0):
                            break
                        (row_count, items_per_row_count) = header
                        for row_index in xrange(row_count):
                            for item_index in xrange(items_per_row_count):
                                (xpos, ) = struct.unpack('<H', data[pos:pos+2])
                                pos += 2
                                (fragment_len,) = struct.unpack('<H', data[pos:pos+2])
                                pos += 2
                                for b in xrange(fragment_len):
                                    framebuffer[ypos + xpos + b] = ord(data[pos + b])
                                pos += fragment_len
                            ypos += width
                           
                    surface = pygame.image.fromstring(framebuffer.tostring(), (width, height), "P")
                    surface.set_palette(pal)
                    pygame.image.save(surface, "data/%s-%i-%i.%s" % (file_type[type], i, frame_index, file_ext[type]))
                    del framebuffer
            else:
                of = open("data/%s-%i.%s" % (file_type[type], i, file_ext[type]), "wb")
                of.write(data)
                of.close()
           del data   

    f.close()



This is a bit of python code to extract the BLB archive. It gives you music, sound, images and animations. I only tested the free demo that you can download here:
http://download.cnet.com/The-Neverhood-demo-large/3000-7564_4-10003341.html
I found the demo decompresses fine with The Unarchiver on MacOS. I assume on Linux you can use Wine, and on Windows you can install it directly.
(I don't have the full game myself. And I don't need a PM of where to find it.)
Most credit go to Valery V. Anisimovsky for finding the archive format, compression method (PKWARE) and ADPCM audio compression.
I found that you can decompress PKWARE stream files with blast, which is in the contrib/blast directory of zlib, and the image and animation format. You need to compile blast into a dynamic library for your platform, so it can be loaded from the python script.
Unfortunately I don't have the time to develop an engine myself. If you're lucky I get the smacker files decoded sometime.
(Update: ffmpeg supports the smacker files in Neverhood.)
(Update: added a few "del" statements to buffers.)
(Update: fixed extension for smacker files.)

Last edited by Onkel Hotte on Sat Aug 29, 2009 7:33 am; edited 2 times in total
 Reply with quote  
Post Fri Aug 28, 2009 10:14 pm 
 View user's profile Send private message
Laserschwert



Joined: 06 Mar 2006
Posts: 260
 

Sorry, I have to ask: Onkel "Kalki" Hotte? Very Happy

 Reply with quote  
Post Fri Aug 28, 2009 11:11 pm 
 View user's profile Send private message
Onkel Hotte



Joined: 28 Aug 2009
Posts: 2
 

Tiny update: The smacker files didn't work in VLC when I tried it, but they work fine with ffmpeg, so they shouldn't be a problem.
The A.BLB in the demo just contains a single image with the Font.

quote:
Originally posted by Laserschwert
Sorry, I have to ask: Onkel "Kalki" Hotte? Very Happy

Yes and no. Did that help?
 Reply with quote  
Post Sat Aug 29, 2009 7:27 am 
 View user's profile Send private message
Laserschwert



Joined: 06 Mar 2006
Posts: 260
 

quote:
Originally posted by Onkel Hotte
Did that help?
Yes and no.
 Reply with quote  
Post Sun Aug 30, 2009 8:54 pm 
 View user's profile Send private message
Jon God



Joined: 27 Oct 2007
Posts: 17
 

I know, this is bumping an ancient thread, but I didn't think my itty bitty question needed a new topic.

My question is just: Is anyone working on The Neverhood support in ScummVM? I got mixed impressions from a few people, so I was curious.

 Reply with quote  
Post Sun Oct 09, 2011 1:24 am 
 View user's profile Send private message AIM Address Yahoo Messenger MSN Messenger
sev
ScummVM Lead


Joined: 21 Sep 2005
Posts: 1791
 

Yes.


Eugene

 Reply with quote  
Post Sun Oct 09, 2011 9:17 am 
 View user's profile Send private message Visit poster's website
ezekiel000



Joined: 25 Aug 2008
Posts: 330
Location: Surrey, England
 

There is a reimplementation outside of scummvm here:
http://github.com/Blaizer/Neverhood/commits/master

 Reply with quote  
Post Sun Oct 09, 2011 9:20 am 
 View user's profile Send private message
  Display posts from previous:      
Reply to topic

Forum Jump:
 
Goto page 1, 2, 3  Next


Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Powered by phpBB © 2001, 2006 phpBB Group
Forum design by ScummVM team, icons by raina
curved edge   curved edge