1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-11-18 02:16:23 -05:00

Standardize indexed color to RGBA conversion to one function (#562)

* Common function for indexed color to rgba

* Use ImgIndexToRGBA when decoding tiles

* Pass DrawEffect down to animation
This commit is contained in:
Ziemas 2020-07-08 23:46:45 +02:00 committed by GitHub
parent f18ede6e66
commit 1ad3c72211
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 83 additions and 103 deletions

View File

@ -8,7 +8,7 @@ const (
// DrawEffectPctTransparency25 is a draw effect that implements the following function: // DrawEffectPctTransparency25 is a draw effect that implements the following function:
// GL_MODULATE; GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA 25 % transparency (colormaps 49-304 in a .pl2) // GL_MODULATE; GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA 25 % transparency (colormaps 49-304 in a .pl2)
DrawEffectPctTransparency25 = iota DrawEffectPctTransparency25 DrawEffect = iota
// DrawEffectPctTransparency50 is a draw effect that implements the following function: // DrawEffectPctTransparency50 is a draw effect that implements the following function:
// GL_MODULATE; GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA 50 % transparency (colormaps 305-560 in a .pl2) // GL_MODULATE; GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA 50 % transparency (colormaps 305-560 in a .pl2)
@ -37,4 +37,7 @@ const (
// DrawEffectMod2X is a draw effect that implements the following function: // DrawEffectMod2X is a draw effect that implements the following function:
// GL_COMBINE_ARB; GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA (colormaps 1457-1712 in a .pl2) // GL_COMBINE_ARB; GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA (colormaps 1457-1712 in a .pl2)
DrawEffectMod2X DrawEffectMod2X
// no effect
DrawEffectNone
) )

View File

@ -1,6 +1,8 @@
package d2interface package d2interface
import "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
type ArchivedAnimationManager interface { type ArchivedAnimationManager interface {
Cacher Cacher
LoadAnimation(animationPath, palettePath string, transparency int) (Animation, error) LoadAnimation(animationPath, palettePath string, drawEffect d2enum.DrawEffect) (Animation, error)
} }

View File

@ -5,6 +5,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common" "github.com/OpenDiablo2/OpenDiablo2/d2common"
@ -36,8 +37,8 @@ func createAnimationManager(renderer d2interface.Renderer) *animationManager {
func (am *animationManager) LoadAnimation( func (am *animationManager) LoadAnimation(
animationPath, palettePath string, animationPath, palettePath string,
transparency int ) (d2interface.Animation, error) { effect d2enum.DrawEffect ) (d2interface.Animation, error) {
cachePath := fmt.Sprintf("%s;%s;%d", animationPath, palettePath, transparency) cachePath := fmt.Sprintf("%s;%s;%d", animationPath, palettePath, effect)
if animation, found := am.cache.Retrieve(cachePath); found { if animation, found := am.cache.Retrieve(cachePath); found {
return animation.(d2interface.Animation).Clone(), nil return animation.(d2interface.Animation).Clone(), nil
} }
@ -62,7 +63,7 @@ func (am *animationManager) LoadAnimation(
return nil, err return nil, err
} }
animation, err = CreateDCCAnimation(am.renderer, animationPath, palette, transparency) animation, err = CreateDCCAnimation(am.renderer, animationPath, palette, effect)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -3,7 +3,6 @@ package d2asset
import ( import (
"errors" "errors"
"fmt" "fmt"
"log"
"strings" "strings"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data"
@ -237,30 +236,17 @@ func (c *Composite) createMode(animationMode, weaponClass string) (*compositeMod
layerValue = "lit" layerValue = "lit"
} }
blend := false drawEffect := d2enum.DrawEffectNone
transparency := 255
if cofLayer.Transparent { if cofLayer.Transparent {
switch cofLayer.DrawEffect { drawEffect = cofLayer.DrawEffect
case d2enum.DrawEffectPctTransparency25:
transparency = 64
case d2enum.DrawEffectPctTransparency50:
transparency = 128
case d2enum.DrawEffectPctTransparency75:
transparency = 192
case d2enum.DrawEffectModulate:
blend = true
default:
log.Println("Unhandled DrawEffect ", cofLayer.DrawEffect, " requested for layer ", cofLayer.Type.String(), " of ", c.token)
}
} }
layer, err := c.loadCompositeLayer(cofLayer.Type.String(), layerValue, animationMode, layer, err := c.loadCompositeLayer(cofLayer.Type.String(), layerValue, animationMode,
cofLayer.WeaponClass.String(), c.palettePath, transparency) cofLayer.WeaponClass.String(), c.palettePath, drawEffect)
if err == nil { if err == nil {
layer.SetPlaySpeed(mode.animationSpeed) layer.SetPlaySpeed(mode.animationSpeed)
layer.PlayForward() layer.PlayForward()
layer.SetBlend(blend)
if err := layer.SetDirection(c.direction); err != nil { if err := layer.SetDirection(c.direction); err != nil {
return nil, err return nil, err
@ -274,7 +260,7 @@ func (c *Composite) createMode(animationMode, weaponClass string) (*compositeMod
} }
func (c *Composite) loadCompositeLayer(layerKey, layerValue, animationMode, weaponClass, func (c *Composite) loadCompositeLayer(layerKey, layerValue, animationMode, weaponClass,
palettePath string, transparency int) (d2interface.Animation, error) { palettePath string, drawEffect d2enum.DrawEffect) (d2interface.Animation, error) {
animationPaths := []string{ animationPaths := []string{
fmt.Sprintf("%s/%s/%s/%s%s%s%s%s.dcc", c.basePath, c.token, layerKey, c.token, layerKey, layerValue, animationMode, weaponClass), fmt.Sprintf("%s/%s/%s/%s%s%s%s%s.dcc", c.basePath, c.token, layerKey, c.token, layerKey, layerValue, animationMode, weaponClass),
fmt.Sprintf("%s/%s/%s/%s%s%s%s%s.dc6", c.basePath, c.token, layerKey, c.token, layerKey, layerValue, animationMode, weaponClass), fmt.Sprintf("%s/%s/%s/%s%s%s%s%s.dc6", c.basePath, c.token, layerKey, c.token, layerKey, layerValue, animationMode, weaponClass),
@ -282,7 +268,7 @@ func (c *Composite) loadCompositeLayer(layerKey, layerValue, animationMode, weap
for _, animationPath := range animationPaths { for _, animationPath := range animationPaths {
if exists, _ := FileExists(animationPath); exists { if exists, _ := FileExists(animationPath); exists {
animation, err := LoadAnimationWithTransparency(animationPath, palettePath, transparency) animation, err := LoadAnimationWithEffect(animationPath, palettePath, drawEffect)
if err == nil { if err == nil {
return animation, nil return animation, nil
} }

View File

@ -104,13 +104,13 @@ func FileExists(filePath string) (bool, error) {
// LoadAnimation loads an animation by its resource path and its palette path // LoadAnimation loads an animation by its resource path and its palette path
func LoadAnimation(animationPath, palettePath string) (d2interface.Animation, error) { func LoadAnimation(animationPath, palettePath string) (d2interface.Animation, error) {
return LoadAnimationWithTransparency(animationPath, palettePath, 255) return LoadAnimationWithEffect(animationPath, palettePath, d2enum.DrawEffectNone)
} }
// LoadAnimationWithTransparency loads an animation by its resource path and its palette path with a given transparency value // LoadAnimationWithEffect loads an animation by its resource path and its palette path with a given transparency value
func LoadAnimationWithTransparency(animationPath, palettePath string, func LoadAnimationWithEffect(animationPath, palettePath string,
transparency int) (d2interface.Animation, error) { drawEffect d2enum.DrawEffect) (d2interface.Animation, error) {
return singleton.animationManager.LoadAnimation(animationPath, palettePath, transparency) return singleton.animationManager.LoadAnimation(animationPath, palettePath, drawEffect)
} }
// LoadComposite creates a composite object from a ObjectLookupRecord and palettePath describing it // LoadComposite creates a composite object from a ObjectLookupRecord and palettePath describing it

View File

@ -82,22 +82,7 @@ func (a *DC6Animation) decodeDirection(directionIndex int) error {
} }
indexData := dc6.DecodeFrame(startFrame + i) indexData := dc6.DecodeFrame(startFrame + i)
colorData := ImgIndexToRGBA(indexData, a.palette)
bytesPerPixel := 4
colorData := make([]byte, int(dc6Frame.Width)*int(dc6Frame.Height)*bytesPerPixel)
for i := 0; i < int(dc6Frame.Width*dc6Frame.Height); i++ {
// Index zero is hardcoded transparent regardless of palette
if indexData[i] == 0 {
continue
}
c := a.palette.GetColors()[indexData[i]]
colorData[i*bytesPerPixel] = c.R()
colorData[i*bytesPerPixel+1] = c.G()
colorData[i*bytesPerPixel+2] = c.B()
colorData[i*bytesPerPixel+3] = c.A()
}
if err := sfc.ReplacePixels(colorData); err != nil { if err := sfc.ReplacePixels(colorData); err != nil {
return err return err

View File

@ -2,9 +2,10 @@ package d2asset
import ( import (
"errors" "errors"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"math" "math"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common" "github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dcc" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dcc"
d2iface "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" d2iface "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
@ -13,16 +14,15 @@ import (
// DCCAnimation represens an animation decoded from DCC // DCCAnimation represens an animation decoded from DCC
type DCCAnimation struct { type DCCAnimation struct {
animation animation
dccPath string dccPath string
transparency int effect d2enum.DrawEffect
palette d2iface.Palette palette d2iface.Palette
renderer d2iface.Renderer renderer d2iface.Renderer
} }
// CreateAnimationFromDCC creates an animation from d2dcc.DCC and d2dat.DATPalette // CreateAnimationFromDCC creates an animation from d2dcc.DCC and d2dat.DATPalette
func CreateDCCAnimation(renderer d2iface.Renderer, dccPath string, palette d2iface.Palette, func CreateDCCAnimation(renderer d2iface.Renderer, dccPath string, palette d2iface.Palette,
transparency int) (d2iface.Animation, error) { effect d2enum.DrawEffect) (d2iface.Animation, error) {
dcc, err := loadDCC(dccPath) dcc, err := loadDCC(dccPath)
if err != nil { if err != nil {
return nil, err return nil, err
@ -35,13 +35,21 @@ func CreateDCCAnimation(renderer d2iface.Renderer, dccPath string, palette d2ifa
} }
DCC := DCCAnimation{ DCC := DCCAnimation{
animation: anim, animation: anim,
dccPath: dccPath, dccPath: dccPath,
palette: palette, palette: palette,
renderer: renderer, renderer: renderer,
transparency: transparency, effect: effect,
} }
// Really the renderer should take DrawEffects and do the right thing
if effect == d2enum.DrawEffectModulate {
DCC.SetBlend(true)
}
// Transparency is now no longer handled, it should be done by using PL2 palette and
// picking the appropriate transform for the transparency level
err = DCC.SetDirection(0) err = DCC.SetDirection(0)
if err != nil { if err != nil {
return nil, err return nil, err
@ -99,25 +107,7 @@ func (a *DCCAnimation) decodeDirection(directionIndex int) error {
frameWidth := maxX - minX frameWidth := maxX - minX
frameHeight := maxY - minY frameHeight := maxY - minY
const bytesPerPixel = 4 pixels := ImgIndexToRGBA(dccFrame.PixelData, a.palette)
pixels := make([]byte, frameWidth*frameHeight*bytesPerPixel)
for y := 0; y < frameHeight; y++ {
for x := 0; x < frameWidth; x++ {
paletteIndex := dccFrame.PixelData[y*frameWidth+x]
if paletteIndex == 0 {
continue
}
palColor := a.palette.GetColors()[paletteIndex]
offset := (x + y*frameWidth) * bytesPerPixel
pixels[offset] = palColor.R()
pixels[offset+1] = palColor.G()
pixels[offset+2] = palColor.B()
pixels[offset+3] = byte(a.transparency)
}
}
sfc, err := a.renderer.NewSurface(frameWidth, frameHeight, d2enum.FilterNearest) sfc, err := a.renderer.NewSurface(frameWidth, frameHeight, d2enum.FilterNearest)
if err != nil { if err != nil {

23
d2core/d2asset/palette.go Normal file
View File

@ -0,0 +1,23 @@
package d2asset
import "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
func ImgIndexToRGBA(indexData []byte, palette d2interface.Palette) []byte {
bytesPerPixel := 4
colorData := make([]byte, len(indexData)*bytesPerPixel)
for i := 0; i < len(indexData); i++ {
// Index zero is hardcoded transparent regardless of palette
if indexData[i] == 0 {
continue
}
c := palette.GetColors()[indexData[i]]
colorData[i*bytesPerPixel] = c.R()
colorData[i*bytesPerPixel+1] = c.G()
colorData[i*bytesPerPixel+2] = c.B()
colorData[i*bytesPerPixel+3] = c.A()
}
return colorData
}

View File

@ -19,15 +19,8 @@ func (mr *MapRenderer) decodeTileGfxData(blocks []d2dt1.Block, pixels *[]byte, t
n := nbpix[y] n := nbpix[y]
length -= n length -= n
for n > 0 { for n > 0 {
colorIndex := block.EncodedData[idx] offset := (((blockY + y + tileYOffset) * tileWidth) + (blockX + x))
if colorIndex != 0 { (*pixels)[offset] = block.EncodedData[idx]
pixelColor := mr.palette.GetColors()[colorIndex]
offset := 4 * (((blockY + y + tileYOffset) * tileWidth) + (blockX + x))
(*pixels)[offset] = pixelColor.R()
(*pixels)[offset+1] = pixelColor.G()
(*pixels)[offset+2] = pixelColor.B()
(*pixels)[offset+3] = 255
}
x++ x++
n-- n--
idx++ idx++
@ -56,17 +49,8 @@ func (mr *MapRenderer) decodeTileGfxData(blocks []d2dt1.Block, pixels *[]byte, t
x += int32(b1) x += int32(b1)
length -= int32(b2) length -= int32(b2)
for b2 > 0 { for b2 > 0 {
colorIndex := block.EncodedData[idx] offset := (((blockY + y + tileYOffset) * tileWidth) + (blockX + x))
if colorIndex != 0 { (*pixels)[offset] = block.EncodedData[idx]
pixelColor := mr.palette.GetColors()[colorIndex]
offset := 4 * (((blockY + y + tileYOffset) * tileWidth) + (blockX + x))
(*pixels)[offset] = pixelColor.R()
(*pixels)[offset+1] = pixelColor.G()
(*pixels)[offset+2] = pixelColor.B()
(*pixels)[offset+3] = 255
}
idx++ idx++
x++ x++
b2-- b2--

View File

@ -7,6 +7,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
) )
func (mr *MapRenderer) generateTileCache() { func (mr *MapRenderer) generateTileCache() {
@ -73,8 +74,10 @@ func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord, tileX,
tileYOffset := d2common.AbsInt32(tileYMinimum) tileYOffset := d2common.AbsInt32(tileYMinimum)
tileHeight := d2common.AbsInt32(tileData[i].Height) tileHeight := d2common.AbsInt32(tileData[i].Height)
image, _ := mr.renderer.NewSurface(int(tileData[i].Width), int(tileHeight), d2enum.FilterNearest) image, _ := mr.renderer.NewSurface(int(tileData[i].Width), int(tileHeight), d2enum.FilterNearest)
pixels := make([]byte, 4*tileData[i].Width*tileHeight) indexData := make([]byte, tileData[i].Width*tileHeight)
mr.decodeTileGfxData(tileData[i].Blocks, &pixels, tileYOffset, tileData[i].Width) mr.decodeTileGfxData(tileData[i].Blocks, &indexData, tileYOffset, tileData[i].Width)
pixels := d2asset.ImgIndexToRGBA(indexData, mr.palette)
_ = image.ReplacePixels(pixels) _ = image.ReplacePixels(pixels)
mr.setImageCacheRecord(tile.Style, tile.Sequence, 0, tileIndex, image) mr.setImageCacheRecord(tile.Style, tile.Sequence, 0, tileIndex, image)
} }
@ -112,8 +115,9 @@ func (mr *MapRenderer) generateShadowCache(tile *d2ds1.FloorShadowRecord, tileX,
} }
image, _ := mr.renderer.NewSurface(int(tileData.Width), tileHeight, d2enum.FilterNearest) image, _ := mr.renderer.NewSurface(int(tileData.Width), tileHeight, d2enum.FilterNearest)
pixels := make([]byte, 4*tileData.Width*int32(tileHeight)) indexData := make([]byte, tileData.Width*int32(tileHeight))
mr.decodeTileGfxData(tileData.Blocks, &pixels, tileYOffset, tileData.Width) mr.decodeTileGfxData(tileData.Blocks, &indexData, tileYOffset, tileData.Width)
pixels := d2asset.ImgIndexToRGBA(indexData, mr.palette)
_ = image.ReplacePixels(pixels) _ = image.ReplacePixels(pixels)
mr.setImageCacheRecord(tile.Style, tile.Sequence, 13, tileIndex, image) mr.setImageCacheRecord(tile.Style, tile.Sequence, 13, tileIndex, image)
} }
@ -173,14 +177,16 @@ func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord, tileX, tileY in
} }
image, _ := mr.renderer.NewSurface(160, int(realHeight), d2enum.FilterNearest) image, _ := mr.renderer.NewSurface(160, int(realHeight), d2enum.FilterNearest)
pixels := make([]byte, 4*160*realHeight) indexData := make([]byte, 160*realHeight)
mr.decodeTileGfxData(tileData.Blocks, &pixels, tileYOffset, 160) mr.decodeTileGfxData(tileData.Blocks, &indexData, tileYOffset, 160)
if newTileData != nil { if newTileData != nil {
mr.decodeTileGfxData(newTileData.Blocks, &pixels, tileYOffset, 160) mr.decodeTileGfxData(newTileData.Blocks, &indexData, tileYOffset, 160)
} }
pixels := d2asset.ImgIndexToRGBA(indexData, mr.palette)
if err := image.ReplacePixels(pixels); err != nil { if err := image.ReplacePixels(pixels); err != nil {
log.Panicf(err.Error()) log.Panicf(err.Error())
} }