From 1eb623cf16b08b077833272f8477b6ffa7214a46 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Tue, 1 Mar 2016 02:09:54 +0900 Subject: [PATCH] Add example 'masking' (#39) --- examples/_resources/images/fiveyears.jpg | Bin 0 -> 31543 bytes examples/_resources/images/license.md | 14 ++- examples/masking/main.go | 141 +++++++++++++++++++++++ graphics.go | 16 ++- internal/graphics/opengl/types.go | 10 +- 5 files changed, 173 insertions(+), 8 deletions(-) create mode 100644 examples/_resources/images/fiveyears.jpg create mode 100644 examples/masking/main.go diff --git a/examples/_resources/images/fiveyears.jpg b/examples/_resources/images/fiveyears.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1c7f8f587f74bbc4874d2dde28ab8124570ae322 GIT binary patch literal 31543 zcmbTdWmFu|5-vKpLvYt2!CitALU4Dt;O_43F2UV{1R30Ikl+r%-5K1uoO5lh_v^h^ zJ*&IcOjUJ#d(W1xs(xR3-voS;7MBtSKtTbZHK8>DfcGsxjF^X|82}(B2cQQ40EhrM zC@cWX2M6_W0HBBfaR2220BI=V|HCUo(f%(PXaFGG5&-+ZWVAo7AM_u~|Iz+mSD1XL z|7$TH`hQD9<>bTsZys>@AHDZ80FR=Dy^FoGg}nm>2Qw>x=ev{~?0>9((0}>Q|7AbT zk;W{?1L|Rq0+7;AAHMs&_W&>v0hdrYFdyDSV?x1TLcI?F$UnS*gZeN1SMB2j1q}lW z2akY=gpBeb0Qv-ghJt~ChJ}HH`_FBld_R5%z+%E-QL>4^V=EaUP&wkT2PPIE0>9Vw z;wn#HQgi%t3PM80!zUml`uv54mX4m2i~B1NFQ4cSF>wh=DQOi|HFXV5Ep1~HQ!{f5 zODks=S2uSLPp{yR(6I1`$f%^`l+?6e=^2@YMa3nhW#tu>^$m@nrskH`w!Z#>!6ESQ z$mq=M-2B4g((=mI_Rj9!{=wnVG34s{=JxLX;qmD|xIWtRf5Q4W|4(H94_ufZxS(NS zVPFydg9{4U{Xf7lVc{s*;ITxM5R4qLsn`P%alR)O)b%0(Ig~GPe>zPg<56>NeTMu8 z+JBM#zXKNZ{|njw0rr1!tpY?pyoUPE=fnB`5DXm5e+d2q2pj@D0s;a&{72WJAR!aOPn&{8{SA zv$A4JcK#|i6-|;j(>_kz_o()-BNHUQZF6w*4nRv2V4=_`JQBjA-{6bM%~p>}6gb>> z*+8)akLiaS<)0=nO0s+Jlvq???K>^xVk^b7`2}^7%U!ONv7>?K7NP>t3kFv_zIEi= z0AaWerw*Ycpnor6pP{ppqauOTF^12sMavWi z=7jcJYOAp!$$IfiKV&5dC;w}J0V8xrQABrVwZzrmaLi@*Eyeru67TX~i7gjhHj+iv zHv7NgbkCe5r~Bmnh!~^r&PVHQS~ejTGLYuWqUC~XZfEm;`YLzyqARZ1)zv|FqDB)Q zq3kHZOneRrws!zxeJcO2yb{-X%O0N+KclDV(PIab6F_o<|aCCY9Z$& ze-yM9wL|L~JqCts=bNHsO6P3db=(okl&I5*BtkC?X~7Ttk@l#j^%_f#dW~%s23_zR z3-Knw+1tteJOZ@6HS;d{01C5@Z_;-uF32i|(w38(9qB~oqs7QveYYTSB0ZD1%LbMNG3U_rF46k}?J85;Nyv-V z{>9}Zt0UVDsq86}EOQ;gAar<%nRY#u?|;hz181Yg`v&RA4BYcmog1A4^*{^3&B81q z363Kb4h)&E3Ow!8qsggUi~5IRstFu(Hx-Ty>DSNWtoajsdD2I>XgGm+69qlYjvU&! zPYe46C7!ld=py?i1Lj=RaxXNQQ!VwYxoBUi_#4e&;+5hTiZdBu&IT#3F~JVTerOzK zNRwOgdv?0P$`+5~is}^EZ;g+k#`+striY$YB?&uS2sn>H!-qzT5&B3~!mI(joR8-u z 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

R9=)X1{zI_+u*WTqu4 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 literal 0 HcmV?d00001 diff --git a/examples/_resources/images/license.md b/examples/_resources/images/license.md index 6c7ad47f8..a5366241e 100644 --- a/examples/_resources/images/license.md +++ b/examples/_resources/images/license.md @@ -28,14 +28,26 @@ Email: info@9031.com http://www.sozai-page.com/02_sozai/b/b04/b04_002/b04_002.html ``` +## fiveyears.jpg + +``` +The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/) +The design is licensed under the Creative Commons 3.0 Attributions license. +Read this article for more details: https://blog.golang.org/gopher +``` + ## gophers.jpg ``` http://blog.golang.org/go-programming-language-turns-two + +Photograph by Chris Nokleberg +the Creative Commons Attribution 3.0 License ``` ## Other image files ``` -Creative Commons Attribution 3.0 License +Copyright 2014 Hajime Hoshi +the Creative Commons Attribution 3.0 License ``` diff --git a/examples/masking/main.go b/examples/masking/main.go new file mode 100644 index 000000000..2789ed676 --- /dev/null +++ b/examples/masking/main.go @@ -0,0 +1,141 @@ +// Copyright 2016 Hajime Hoshi +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "image" + "image/color" + _ "image/jpeg" + "log" + "math" + + "github.com/hajimehoshi/ebiten" + "github.com/hajimehoshi/ebiten/ebitenutil" +) + +const ( + screenWidth = 320 + screenHeight = 240 +) + +var ( + gophersImage *ebiten.Image + fiveyearsImage *ebiten.Image + maskImage *ebiten.Image + spotLightImage *ebiten.Image + spotLightX = 0 + spotLightY = 0 + spotLightVX = 1 + spotLightVY = 1 +) + +func update(screen *ebiten.Image) error { + spotLightX += spotLightVX + spotLightY += spotLightVY + if spotLightX < 0 { + spotLightX = -spotLightX + spotLightVX = -spotLightVX + } + if spotLightY < 0 { + spotLightY = -spotLightY + spotLightVY = -spotLightVY + } + w, h := spotLightImage.Size() + maxX, maxY := screenWidth-w, screenHeight-h + if maxX < spotLightX { + spotLightX = -spotLightX + 2*maxX + spotLightVX = -spotLightVX + } + if maxY < spotLightY { + spotLightY = -spotLightY + 2*maxY + spotLightVY = -spotLightVY + } + + if err := maskImage.Clear(); err != nil { + return err + } + + op := &ebiten.DrawImageOptions{} + op.GeoM.Translate(float64(spotLightX), float64(spotLightY)) + if err := maskImage.DrawImage(spotLightImage, op); err != nil { + return err + } + + op = &ebiten.DrawImageOptions{} + op.CompositionMode = ebiten.CompositionModeSourceOut + if err := maskImage.DrawImage(fiveyearsImage, op); err != nil { + return err + } + + if err := screen.Fill(color.RGBA{0x00, 0x00, 0x80, 0xff}); err != nil { + return err + } + if err := screen.DrawImage(gophersImage, &ebiten.DrawImageOptions{}); err != nil { + return err + } + if err := screen.DrawImage(maskImage, &ebiten.DrawImageOptions{}); err != nil { + return err + } + + return nil +} + +func max(a, b int) int { + if a < b { + return b + } + return a +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func main() { + var err error + gophersImage, _, err = ebitenutil.NewImageFromFile("_resources/images/gophers.jpg", ebiten.FilterNearest) + if err != nil { + log.Fatal(err) + } + fiveyearsImage, _, err = ebitenutil.NewImageFromFile("_resources/images/fiveyears.jpg", ebiten.FilterNearest) + if err != nil { + log.Fatal(err) + } + maskImage, err = ebiten.NewImage(screenWidth, screenHeight, ebiten.FilterNearest) + if err != nil { + log.Fatal(err) + } + + as := image.Point{128, 128} + a := image.NewAlpha(image.Rectangle{image.ZP, as}) + for j := 0; j < as.Y; j++ { + for i := 0; i < as.X; i++ { + r := as.X / 2 + d := math.Sqrt(float64((i-r)*(i-r) + (j-r)*(j-r))) + b := uint8(max(0, min(0xff, 3*0xff-int(d*3*0xff)/r))) + a.SetAlpha(i, j, color.Alpha{b}) + } + } + spotLightImage, err = ebiten.NewImageFromImage(a, ebiten.FilterNearest) + if err != nil { + log.Fatal(err) + } + if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Masking (Ebiten Demo)"); err != nil { + log.Fatal(err) + } +} diff --git a/graphics.go b/graphics.go index ea93f8a14..81aa058b4 100644 --- a/graphics.go +++ b/graphics.go @@ -39,7 +39,19 @@ func glFilter(c *opengl.Context, filter Filter) opengl.Filter { // CompositionMode represents Porter-Duff composition mode. type CompositionMode int +// Note: This name convention follow CSS compositing: https://drafts.fxtf.org/compositing-2/ + const ( - CompositionModeSourceOver CompositionMode = CompositionMode(opengl.CompositionModeSourceOver) // regular alpha blending - CompositionModeLighter = CompositionMode(opengl.CompositionModeLighter) // sum of source and destination (a.k.a. 'plus' or 'additive') + CompositionModeSourceOver CompositionMode = CompositionMode(opengl.CompositionModeSourceOver) // regular alpha blending + CompositionModeClear = CompositionMode(opengl.CompositionModeClear) + CompositionModeCopy = CompositionMode(opengl.CompositionModeCopy) + CompositionModeDestination = CompositionMode(opengl.CompositionModeDestination) + CompositionModeSourceIn = CompositionMode(opengl.CompositionModeSourceIn) + CompositionModeDestinationIn = CompositionMode(opengl.CompositionModeDestinationIn) + CompositionModeSourceOut = CompositionMode(opengl.CompositionModeSourceOut) + CompositionModeDestinationOut = CompositionMode(opengl.CompositionModeDestinationOut) + CompositionModeSourceAtop = CompositionMode(opengl.CompositionModeSourceAtop) + CompositionModeDestinationAtop = CompositionMode(opengl.CompositionModeDestinationAtop) + CompositionModeXor = CompositionMode(opengl.CompositionModeXor) + CompositionModeLighter = CompositionMode(opengl.CompositionModeLighter) // sum of source and destination (a.k.a. 'plus' or 'additive') ) diff --git a/internal/graphics/opengl/types.go b/internal/graphics/opengl/types.go index 1485efc09..d5fb7e9f8 100644 --- a/internal/graphics/opengl/types.go +++ b/internal/graphics/opengl/types.go @@ -47,8 +47,8 @@ const ( CompositionModeSourceOver CompositionMode = iota // This value must be 0 (= initial value) CompositionModeClear CompositionModeCopy - CompositionModeDesination - CompositionModeDesinationOver + CompositionModeDestination + CompositionModeDestinationOver CompositionModeSourceIn CompositionModeDestinationIn CompositionModeSourceOut @@ -68,10 +68,10 @@ func (c *Context) operations(mode CompositionMode) (src operation, dst operation return c.zero, c.zero case CompositionModeCopy: return c.one, c.zero - case CompositionModeDesination: + case CompositionModeDestination: return c.zero, c.one - case CompositionModeDesinationOver: - return c.one, c.oneMinusDstAlpha + case CompositionModeDestinationOver: + return c.oneMinusDstAlpha, c.one case CompositionModeSourceIn: return c.dstAlpha, c.zero case CompositionModeDestinationIn: