1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-09-21 18:56:15 -04: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:
// 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:
// 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:
// GL_COMBINE_ARB; GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA (colormaps 1457-1712 in a .pl2)
DrawEffectMod2X
// no effect
DrawEffectNone
)

View File

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

View File

@ -3,7 +3,6 @@ package d2asset
import (
"errors"
"fmt"
"log"
"strings"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data"
@ -237,30 +236,17 @@ func (c *Composite) createMode(animationMode, weaponClass string) (*compositeMod
layerValue = "lit"
}
blend := false
transparency := 255
drawEffect := d2enum.DrawEffectNone
if cofLayer.Transparent {
switch 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)
}
drawEffect = cofLayer.DrawEffect
}
layer, err := c.loadCompositeLayer(cofLayer.Type.String(), layerValue, animationMode,
cofLayer.WeaponClass.String(), c.palettePath, transparency)
cofLayer.WeaponClass.String(), c.palettePath, drawEffect)
if err == nil {
layer.SetPlaySpeed(mode.animationSpeed)
layer.PlayForward()
layer.SetBlend(blend)
if err := layer.SetDirection(c.direction); err != nil {
return nil, err
@ -274,7 +260,7 @@ func (c *Composite) createMode(animationMode, weaponClass string) (*compositeMod
}
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{
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),
@ -282,7 +268,7 @@ func (c *Composite) loadCompositeLayer(layerKey, layerValue, animationMode, weap
for _, animationPath := range animationPaths {
if exists, _ := FileExists(animationPath); exists {
animation, err := LoadAnimationWithTransparency(animationPath, palettePath, transparency)
animation, err := LoadAnimationWithEffect(animationPath, palettePath, drawEffect)
if err == 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
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
func LoadAnimationWithTransparency(animationPath, palettePath string,
transparency int) (d2interface.Animation, error) {
return singleton.animationManager.LoadAnimation(animationPath, palettePath, transparency)
// LoadAnimationWithEffect loads an animation by its resource path and its palette path with a given transparency value
func LoadAnimationWithEffect(animationPath, palettePath string,
drawEffect d2enum.DrawEffect) (d2interface.Animation, error) {
return singleton.animationManager.LoadAnimation(animationPath, palettePath, drawEffect)
}
// 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)
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()
}
colorData := ImgIndexToRGBA(indexData, a.palette)
if err := sfc.ReplacePixels(colorData); err != nil {
return err

View File

@ -2,9 +2,10 @@ package d2asset
import (
"errors"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"math"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dcc"
d2iface "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
@ -13,16 +14,15 @@ import (
// DCCAnimation represens an animation decoded from DCC
type DCCAnimation struct {
animation
dccPath string
transparency int
palette d2iface.Palette
renderer d2iface.Renderer
dccPath string
effect d2enum.DrawEffect
palette d2iface.Palette
renderer d2iface.Renderer
}
// CreateAnimationFromDCC creates an animation from d2dcc.DCC and d2dat.DATPalette
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)
if err != nil {
return nil, err
@ -35,13 +35,21 @@ func CreateDCCAnimation(renderer d2iface.Renderer, dccPath string, palette d2ifa
}
DCC := DCCAnimation{
animation: anim,
dccPath: dccPath,
palette: palette,
renderer: renderer,
transparency: transparency,
animation: anim,
dccPath: dccPath,
palette: palette,
renderer: renderer,
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)
if err != nil {
return nil, err
@ -99,25 +107,7 @@ func (a *DCCAnimation) decodeDirection(directionIndex int) error {
frameWidth := maxX - minX
frameHeight := maxY - minY
const bytesPerPixel = 4
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)
}
}
pixels := ImgIndexToRGBA(dccFrame.PixelData, a.palette)
sfc, err := a.renderer.NewSurface(frameWidth, frameHeight, d2enum.FilterNearest)
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]
length -= n
for n > 0 {
colorIndex := block.EncodedData[idx]
if colorIndex != 0 {
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
}
offset := (((blockY + y + tileYOffset) * tileWidth) + (blockX + x))
(*pixels)[offset] = block.EncodedData[idx]
x++
n--
idx++
@ -56,17 +49,8 @@ func (mr *MapRenderer) decodeTileGfxData(blocks []d2dt1.Block, pixels *[]byte, t
x += int32(b1)
length -= int32(b2)
for b2 > 0 {
colorIndex := block.EncodedData[idx]
if colorIndex != 0 {
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
}
offset := (((blockY + y + tileYOffset) * tileWidth) + (blockX + x))
(*pixels)[offset] = block.EncodedData[idx]
idx++
x++
b2--

View File

@ -7,6 +7,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
)
func (mr *MapRenderer) generateTileCache() {
@ -73,8 +74,10 @@ func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord, tileX,
tileYOffset := d2common.AbsInt32(tileYMinimum)
tileHeight := d2common.AbsInt32(tileData[i].Height)
image, _ := mr.renderer.NewSurface(int(tileData[i].Width), int(tileHeight), d2enum.FilterNearest)
pixels := make([]byte, 4*tileData[i].Width*tileHeight)
mr.decodeTileGfxData(tileData[i].Blocks, &pixels, tileYOffset, tileData[i].Width)
indexData := make([]byte, tileData[i].Width*tileHeight)
mr.decodeTileGfxData(tileData[i].Blocks, &indexData, tileYOffset, tileData[i].Width)
pixels := d2asset.ImgIndexToRGBA(indexData, mr.palette)
_ = image.ReplacePixels(pixels)
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)
pixels := make([]byte, 4*tileData.Width*int32(tileHeight))
mr.decodeTileGfxData(tileData.Blocks, &pixels, tileYOffset, tileData.Width)
indexData := make([]byte, tileData.Width*int32(tileHeight))
mr.decodeTileGfxData(tileData.Blocks, &indexData, tileYOffset, tileData.Width)
pixels := d2asset.ImgIndexToRGBA(indexData, mr.palette)
_ = image.ReplacePixels(pixels)
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)
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 {
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 {
log.Panicf(err.Error())
}