love2d教程23--金庸群侠资源格式解析2

上篇,今天又折腾了半天,终于可以解析grp文件了。 “金”的图片编码方式为rle8(行程编码),

一个grp文件里存放一系列的图片, 图片编码的格式为:

起始8个字节 

xxxx   xxxx   xxxx   xxxx       --xxxx表示两位二进制数,也是大端格式

宽       高      x偏移  y偏移

剩下的表示颜色数据,按行编码,每一行的第一个字节表示当前行所占的字节数, 第二个字节表示

透明点的个数,接着的字节表示颜色点的个数,然后是颜色点的 颜色值,如此反复。

ssss                 xxxx         yyyy       zz.......zz   ssss    xxxx   yyyy   zz......zz ......

本行所占字节  透明点字节   颜色点字节   像素值     如此反复  

 

于是我便开始尝试解析第一幅图片,可是居然费了很久也没成功,关键是想的复杂了, 后来看了一下

游泳的鱼前辈“金”sdl复刻版里的解析代码,才写来了出来,在这里向 前辈致谢。可是第一幅图片显示

时,颜色却是灰的,我又仔细排错,并没有找到逻辑 里的问题,于是把颜色的bgr,改成了rgb,居然

正常了,看来颜色是rgb顺序。最终调试完成,可是发现有些图片显示会出现黑点,暂时不知什么原因。

   

注意运行时要在工程目录使用"love ." ,否则有可能提示错误。  

由于解析时涉及了十六进制,采用了dialectronics 的BinDecHex库,并做了一点修改。

代码如下,点击下载

 main.lua

require('grp')
--创建一个grp
hdgrp=grp:new()
function love.load()
    image=hdgrp:getImg(1,"hdgrp") --读取第一张图片
end

function love.draw()
    love.graphics.draw(image,100,100)
end

grp.lua

local bit=require('BinDecHex')
require('mmapcol')
grp={idx={},filename="",imgs={}}
function grp:new(o)
    o = o or {} --如果参数中没有提供table,则创建一个空的。
     --将新对象实例的metatable指向表(类)
     setmetatable(o,self)
     self.__index = self
     --最后返回构造后的对象实例
     return o
end
--filename文件名不需要后缀,从idx文件创建idx表
function grp:createIdx(filename)
    local file=assert(io.open(filename..".idx","rb"))
    local current = file:seek()  --保存当前文件首地址
    local size = file:seek("end")   -- 得到文件长度
    file:seek("set", current)       -- 恢复
    
    
    table.insert(self.idx,0) --第一个图像的地址实际是0
    local block=4 --设置文件偏移
    local num=size/block --一共多少个图像
    local tmp="" --存放临时4字节数据
    local data="" --存放tmp逆序后的数据
    
    for i=1,num do
        local bytes=file:read(block)
        --把每个byte都转完16进制数
        for b in string.gfind(bytes,".") do
            tmp=tmp ..string.format("%02x", string.byte(b))
        end
        
        --大端转小端
        data= string.sub(tmp,7,8) ..string.sub(tmp,5,6)..string.sub(tmp,3,4)..    string.sub(tmp,1,2) 
        --16进制数转10进制数存入self.idx
        table.insert(self.idx,bit.H2D(data))
        tmp="" --清空
        
        file:seek("set",block*i) --移动文件位置
    
    end
    
    file:close()
end
--从grp文件创建图像 index索引,filename文件名不要后缀
--返回Image类型,图片的偏移ox,oy
function grp:getImg(index,filename)

    local file=assert(io.open(filename..".grp","rb"))
    self:createIdx(filename)
    self.filename=filename
    local addr=self.idx[index] --获取图像地址
    if not addr then
        print("index is bigger")
    end
    local block=self.idx[index+1]-addr --获取图像占用字节数
    --移动文件地址
    file:seek("set",addr)
    local imgInfo=file:read(8) --读取前8个字节的图像信息
    local infostr=""
    for b in string.gfind(imgInfo,".") do
        infostr=infostr..string.format("%02x", string.byte(b))
    end
    local w,h=0,0 --图像的宽和高
    w=bit.H2D(string.sub(infostr,3,4)..string.sub(infostr,1,2))
    h=bit.H2D(string.sub(infostr,7,8)..string.sub(infostr,5,6))
    
    --用infostr="00000000f2ff2d00"测试通过
    local ox,oy=0,0 --图像的偏移
    --这里有的偏移是负数要判断
    if string.find(infostr,"ff",11,12) then
        local hex=string.sub(infostr,11,12)..string.sub(infostr,9,10)
        ox=-(bit.H2D(bit.BNot(hex))+1) --补码原理
    else
        ox=bit.H2D(string.sub(infostr,9,10))
    end
    if string.find(infostr,"ff",15,16) then
    local hex=string.sub(infostr,15,16)..string.sub(infostr,13,14)
        oy=-(bit.H2D(bit.BNot(hex))+1) --补码原理
    else
        oy=bit.H2D(string.sub(infostr,13,14))
    end
    

--先初始化为透明的图片
    imgdata=love.image.newImageData(w,h)
    for y=0,h-1 do
        for x=0,w-1 do --48,112,112,0
        imgdata:setPixel(x,y,0,0,0,0) --todo ,0还是255
        end
    end
    
    --读取索引为index的图像
    local data={}
    file:seek("set",addr)
    local bytes=file:read(block)
    local tmpstr=""
    --读取第一个图片
    for b in string.gfind(bytes,".") do
        table.insert(data,tonumber(string.format("%03d", string.byte(b))))
    end

    file:close()

    local row=0 --保存每行的字节数
    local p=9 --指向data里的数据里的颜色起始点
    local ks=0 --空白点个数
    local solidnum=0 --颜色点个数
    local nilc=0 --保存空白点个数
    local start=0
    for i=0,h do
        row=data[p] --i行的数据个数
        start=p
        p=p+1 --移动到下一点
        if row> 0 then --i行的数据都是颜色点,如果是透明点则为0
             ks=0
             while(1) do
                ks=ks+data[p] --当前行空白点的个数
                nilc=ks
                if ks>=w-1 then -- i行宽度到头,结束
                break
                end
            
                p=p+1 --移动到下一点 ,颜色点
                solidnum=data[p]  -- 不透明点个数
            
                p=p+1 --现在指向不透明点的颜色
                for j=0,solidnum-1 do
            
                imgdata:setPixel(j+nilc,i,mmapcol[data[p]][1],mmapcol[data[p]][2],mmapcol[data[p]][3],255)
                --移动到下一点
                ks=ks+1 --颜色点结束,便是透明点
                p=p+1
                end
            
                   if(ks>=w) then
                        break -- i行宽度到头,结束
                   end
                   --todo
                    if(p-start>=row) then
                        break    --i行没有数据,结束
                    end
            end
            if p>=#data then
            break
            end
        end
    
    end
    
    return love.graphics.newImage(imgdata),ox,oy    
end

 

    

posted @ 2013-03-29 19:58  半山th  阅读(1874)  评论(0编辑  收藏  举报