Go で書き直した Ikemen
Revision | abf1f49b3c2f7ef567e8db46e36d07a3d193080f (tree) |
---|---|
Time | 2016-11-08 23:16:36 |
Author | SUEHIRO <supersuehiro@user...> |
Commiter | SUEHIRO |
画像の表示テスト
@@ -1,4 +1,3 @@ | ||
1 | 1 | /data |
2 | 2 | /go |
3 | -/godoc.txt | |
4 | 3 | /sound |
@@ -2,5 +2,5 @@ | ||
2 | 2 | GOPATH=$PWD/go |
3 | 3 | export GOPATH |
4 | 4 | go fmt ./src/*.go |
5 | -godoc -src ./src .* > godoc.txt | |
6 | -go generate ./src/*.go && GODEBUG=cgocheck=0 go run ./src/*.go | |
5 | +# godoc -src ./src .* > godoc.txt | |
6 | +go generate ./src/main.go && GODEBUG=cgocheck=0 go run ./src/*.go |
@@ -1,7 +1,17 @@ | ||
1 | 1 | package main |
2 | 2 | |
3 | -type Error string | |
3 | +import "math" | |
4 | 4 | |
5 | -func (e Error) Error() string { | |
6 | - return string(e) | |
5 | +func Abs(f float32) float32 { | |
6 | + if f < 0 { | |
7 | + return -f | |
8 | + } | |
9 | + return f | |
10 | +} | |
11 | +func IsFinite(f float32) bool { | |
12 | + return math.Abs(float64(f)) <= math.MaxFloat64 | |
7 | 13 | } |
14 | + | |
15 | +type Error string | |
16 | + | |
17 | +func (e Error) Error() string { return string(e) } |
@@ -4,6 +4,7 @@ import "os" | ||
4 | 4 | |
5 | 5 | var AppendFunc = [...][2]string{ |
6 | 6 | {"I", "int"}, |
7 | + {"U32", "uint32"}, | |
7 | 8 | {"Pal", "[]uint32"}, |
8 | 9 | } |
9 | 10 |
@@ -11,6 +11,17 @@ func AppendI(slice *[]int, data ...int) { | ||
11 | 11 | *slice = (*slice)[:n] |
12 | 12 | copy((*slice)[m:n], data) |
13 | 13 | } |
14 | +func AppendU32(slice *[]uint32, data ...uint32) { | |
15 | + m := len(*slice) | |
16 | + n := m + len(data) | |
17 | + if n > cap(*slice) { | |
18 | + newSlice := make([]uint32, n+n/4) | |
19 | + copy(newSlice, *slice) | |
20 | + *slice = newSlice | |
21 | + } | |
22 | + *slice = (*slice)[:n] | |
23 | + copy((*slice)[m:n], data) | |
24 | +} | |
14 | 25 | func AppendPal(slice *[][]uint32, data ...[]uint32) { |
15 | 26 | m := len(*slice) |
16 | 27 | n := m + len(data) |
@@ -5,120 +5,14 @@ package main | ||
5 | 5 | import "C" |
6 | 6 | import ( |
7 | 7 | "encoding/binary" |
8 | + "fmt" | |
8 | 9 | "github.com/go-gl/gl/v2.1/gl" |
9 | - "image" | |
10 | - "image/draw" | |
11 | - "image/png" | |
12 | 10 | "io" |
13 | 11 | "os" |
14 | 12 | "runtime" |
15 | - "strings" | |
16 | 13 | "unsafe" |
17 | 14 | ) |
18 | 15 | |
19 | -func gltest() { | |
20 | - vertShader := strings.Join([]string{ | |
21 | - "void main(void){", | |
22 | - "gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;", | |
23 | - "gl_Position = ftransform();", | |
24 | - "}\x00"}, "") | |
25 | - fragShader := strings.Join([]string{ | |
26 | - "uniform float a;", | |
27 | - "uniform sampler2D tex;", | |
28 | - "uniform sampler1D pal;", | |
29 | - "uniform int msk;", | |
30 | - "void main(void){", | |
31 | - "float r = texture2D(tex, gl_TexCoord[0].st).r;", | |
32 | - "vec4 c;", | |
33 | - "gl_FragColor =", | |
34 | - "int(255.0*r) == msk ? vec4(0.0)", | |
35 | - ": (c = texture1D(pal, r*0.9961), vec4(c.b, c.g, c.r, a));", | |
36 | - "}\x00"}, "") | |
37 | - fragShaderFc := strings.Join([]string{ | |
38 | - "uniform float a;", | |
39 | - "uniform sampler2D tex;", | |
40 | - "uniform bool neg;", | |
41 | - "uniform float gray;", | |
42 | - "uniform vec3 add;", | |
43 | - "uniform vec3 mul;", | |
44 | - "void main(void){", | |
45 | - "vec4 c = texture2D(tex, gl_TexCoord[0].st);", | |
46 | - "if(neg) c.rgb = vec3(1.0) - c.rgb;", | |
47 | - "float gcol = (c.r + c.g + c.b) / 3.0;", | |
48 | - "c.r += (gcol - c.r) * gray + add.r;", | |
49 | - "c.g += (gcol - c.g) * gray + add.g;", | |
50 | - "c.b += (gcol - c.b) * gray + add.b;", | |
51 | - "c.rgb *= mul;", | |
52 | - "c.a *= a;", | |
53 | - "gl_FragColor = c;", | |
54 | - "}\x00"}, "") | |
55 | - fragShaderFcS := strings.Join([]string{ | |
56 | - "uniform float a;", | |
57 | - "uniform sampler2D tex;", | |
58 | - "uniform vec3 color;", | |
59 | - "void main(void){", | |
60 | - "vec4 c = texture2D(tex, gl_TexCoord[0].st);", | |
61 | - "c.rgb = color * c.a;", | |
62 | - "c.a *= a;", | |
63 | - "gl_FragColor = c;", | |
64 | - "}\x00"}, "") | |
65 | - errLog := func(obl uintptr) error { | |
66 | - var size int32 | |
67 | - gl.GetObjectParameterivARB(obl, gl.INFO_LOG_LENGTH, &size) | |
68 | - if size <= 0 { | |
69 | - return nil | |
70 | - } | |
71 | - var l int32 | |
72 | - str := make([]byte, size+1) | |
73 | - gl.GetInfoLogARB(obl, size, &l, &str[0]) | |
74 | - return Error(str[:l]) | |
75 | - } | |
76 | - compile := func(shaderType uint32, src string) (shader uintptr) { | |
77 | - shader = gl.CreateShaderObjectARB(shaderType) | |
78 | - s, l := gl.Str(src), int32(len(src)-1) | |
79 | - gl.ShaderSourceARB(shader, 1, &s, &l) | |
80 | - gl.CompileShaderARB(shader) | |
81 | - var ok int32 | |
82 | - gl.GetObjectParameterivARB(shader, gl.OBJECT_COMPILE_STATUS_ARB, &ok) | |
83 | - if ok == 0 { | |
84 | - chk(errLog(shader)) | |
85 | - panic(Error("コンパイルエラー")) | |
86 | - } | |
87 | - return | |
88 | - } | |
89 | - link := func(v uintptr, f uintptr) (program uintptr) { | |
90 | - program = gl.CreateProgramObjectARB() | |
91 | - gl.AttachObjectARB(program, v) | |
92 | - gl.AttachObjectARB(program, f) | |
93 | - gl.LinkProgramARB(program) | |
94 | - var ok int32 | |
95 | - gl.GetObjectParameterivARB(program, gl.OBJECT_LINK_STATUS_ARB, &ok) | |
96 | - if ok == 0 { | |
97 | - chk(errLog(program)) | |
98 | - panic(Error("リンクエラー")) | |
99 | - } | |
100 | - return | |
101 | - } | |
102 | - vertObj := compile(gl.VERTEX_SHADER, vertShader) | |
103 | - fragObj := compile(gl.FRAGMENT_SHADER, fragShader) | |
104 | - shader := link(vertObj, fragObj) | |
105 | - gl.GetUniformLocationARB(shader, gl.Str("pal\x00")) | |
106 | - gl.GetUniformLocationARB(shader, gl.Str("msk\x00")) | |
107 | - gl.DeleteObjectARB(fragObj) | |
108 | - fragObj = compile(gl.FRAGMENT_SHADER, fragShaderFc) | |
109 | - shaderFc := link(vertObj, fragObj) | |
110 | - gl.GetUniformLocationARB(shaderFc, gl.Str("neg\x00")) | |
111 | - gl.GetUniformLocationARB(shaderFc, gl.Str("gray\x00")) | |
112 | - gl.GetUniformLocationARB(shaderFc, gl.Str("add\x00")) | |
113 | - gl.GetUniformLocationARB(shaderFc, gl.Str("mul\x00")) | |
114 | - gl.DeleteObjectARB(fragObj) | |
115 | - fragObj = compile(gl.FRAGMENT_SHADER, fragShaderFcS) | |
116 | - shaderFcS := link(vertObj, fragObj) | |
117 | - gl.GetUniformLocationARB(shaderFcS, gl.Str("color\x00")) | |
118 | - gl.DeleteObjectARB(fragObj) | |
119 | - gl.DeleteObjectARB(vertObj) | |
120 | -} | |
121 | - | |
122 | 16 | type Texture uint32 |
123 | 17 | |
124 | 18 | func textureFinalizer(t *Texture) { |
@@ -128,29 +22,24 @@ func textureFinalizer(t *Texture) { | ||
128 | 22 | } |
129 | 23 | func NewTexture() (t *Texture) { |
130 | 24 | t = new(Texture) |
25 | + gl.GenTextures(1, (*uint32)(t)) | |
131 | 26 | runtime.SetFinalizer(t, textureFinalizer) |
132 | 27 | return |
133 | 28 | } |
134 | -func (t *Texture) FromImageRGBA(rgba *image.RGBA) { | |
135 | - gl.BindTexture(gl.TEXTURE_2D, uint32(*t)) | |
136 | - gl.PixelStorei(gl.UNPACK_ALIGNMENT, 1) | |
137 | - gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, | |
138 | - int32(rgba.Bounds().Dx()), int32(rgba.Bounds().Dy()), | |
139 | - 0, gl.RGBA, gl.UNSIGNED_BYTE, unsafe.Pointer(&rgba.Pix[0])) | |
140 | - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) | |
141 | - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) | |
142 | - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP) | |
143 | - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP) | |
144 | -} | |
145 | -func (t *Texture) FromImage(im image.Image) { | |
146 | - switch trueim := im.(type) { | |
147 | - case *image.RGBA: | |
148 | - t.FromImageRGBA(trueim) | |
149 | - default: | |
150 | - copy := image.NewRGBA(trueim.Bounds()) | |
151 | - draw.Draw(copy, trueim.Bounds(), trueim, image.Pt(0, 0), draw.Src) | |
152 | - t.FromImageRGBA(copy) | |
29 | + | |
30 | +type PalFX struct{} | |
31 | + | |
32 | +func (fx *PalFX) GetFcPalFx(trans int32) (neg bool, color float32, | |
33 | + add, mul [3]float32) { | |
34 | + neg = false | |
35 | + color = 1 | |
36 | + for i := range add { | |
37 | + add[i] = 0 | |
38 | + } | |
39 | + for i := range mul { | |
40 | + mul[i] = 1 | |
153 | 41 | } |
42 | + return | |
154 | 43 | } |
155 | 44 | |
156 | 45 | type PalleteList struct { |
@@ -159,7 +48,7 @@ type PalleteList struct { | ||
159 | 48 | PalTable map[[2]int16]int |
160 | 49 | } |
161 | 50 | |
162 | -func (pl *PalleteList) Clear() { | |
51 | +func (pl *PalleteList) init() { | |
163 | 52 | pl.palletes = nil |
164 | 53 | pl.palleteMap = nil |
165 | 54 | pl.PalTable = make(map[[2]int16]int) |
@@ -306,6 +195,128 @@ type Sprite struct { | ||
306 | 195 | func NewSprite() *Sprite { |
307 | 196 | return &Sprite{palidx: -1, link: -1} |
308 | 197 | } |
198 | +func LoadFromSff(filename string, g int16, n int16) (*Sprite, error) { | |
199 | + s := NewSprite() | |
200 | + f, err := os.Open(filename) | |
201 | + if err != nil { | |
202 | + return nil, err | |
203 | + } | |
204 | + defer func() { chk(f.Close()) }() | |
205 | + h := &SffHeader{} | |
206 | + var lofs, tofs uint32 | |
207 | + if err := h.Read(f, &lofs, &tofs); err != nil { | |
208 | + return nil, err | |
209 | + } | |
210 | + var shofs, xofs, size uint32 = h.FirstSpriteHeaderOffset, 0, 0 | |
211 | + var indexOfPrevious uint16 | |
212 | + pl := &PalleteList{} | |
213 | + pl.init() | |
214 | + foo := func() error { | |
215 | + switch h.Ver0 { | |
216 | + case 1: | |
217 | + if err := s.readHeader(f, &xofs, &size, &indexOfPrevious); err != nil { | |
218 | + return err | |
219 | + } | |
220 | + case 2: | |
221 | + if err := s.readHeaderV2(f, &xofs, &size, | |
222 | + lofs, tofs, &indexOfPrevious); err != nil { | |
223 | + return err | |
224 | + } | |
225 | + } | |
226 | + return nil | |
227 | + } | |
228 | + var palletSame bool | |
229 | + var dummy *Sprite | |
230 | + var newSubHeaderOffset []uint32 | |
231 | + AppendU32(&newSubHeaderOffset, shofs) | |
232 | + i := 0 | |
233 | + for ; i < int(h.NumberOfSprites); i++ { | |
234 | + AppendU32(&newSubHeaderOffset, shofs) | |
235 | + f.Seek(int64(shofs), 0) | |
236 | + if err := foo(); err != nil { | |
237 | + return nil, err | |
238 | + } | |
239 | + if s.palidx < 0 || s.Group == g && s.Number == n { | |
240 | + ip := len(newSubHeaderOffset) | |
241 | + for size == 0 { | |
242 | + if int(indexOfPrevious) >= ip { | |
243 | + return nil, Error("linkが不正です") | |
244 | + } | |
245 | + ip = int(indexOfPrevious) | |
246 | + if h.Ver0 == 1 { | |
247 | + shofs = newSubHeaderOffset[ip] | |
248 | + } else { | |
249 | + shofs = h.FirstSpriteHeaderOffset + uint32(ip)*28 | |
250 | + } | |
251 | + f.Seek(int64(shofs), 0) | |
252 | + if err := foo(); err != nil { | |
253 | + return nil, err | |
254 | + } | |
255 | + } | |
256 | + switch h.Ver0 { | |
257 | + case 1: | |
258 | + if err := s.read(f, h, int64(shofs+32), size, xofs, dummy, | |
259 | + &palletSame, pl, false); err != nil { | |
260 | + return nil, err | |
261 | + } | |
262 | + case 2: | |
263 | + if err := s.readV2(f, int64(xofs), size); err != nil { | |
264 | + return nil, err | |
265 | + } | |
266 | + } | |
267 | + if s.Group == g && s.Number == n { | |
268 | + break | |
269 | + } | |
270 | + dummy = &Sprite{palidx: s.palidx} | |
271 | + } | |
272 | + if h.Ver0 == 1 { | |
273 | + shofs = xofs | |
274 | + } else { | |
275 | + shofs += 28 | |
276 | + } | |
277 | + } | |
278 | + if i == int(h.NumberOfSprites) { | |
279 | + return nil, Error(fmt.Sprintf("%d, %d のスプライトが見つかりません", g, n)) | |
280 | + } | |
281 | + if h.Ver0 == 1 { | |
282 | + s.Pal = pl.Get(s.palidx) | |
283 | + s.palidx = -1 | |
284 | + return s, nil | |
285 | + } | |
286 | + read := func(x interface{}) error { | |
287 | + return binary.Read(f, binary.LittleEndian, x) | |
288 | + } | |
289 | + size = 0 | |
290 | + indexOfPrevious = uint16(s.palidx) | |
291 | + ip := indexOfPrevious + 1 | |
292 | + for size == 0 && ip != indexOfPrevious { | |
293 | + ip = indexOfPrevious | |
294 | + shofs = h.FirstPaletteHeaderOffset + uint32(ip)*16 | |
295 | + f.Seek(int64(shofs)+6, 0) | |
296 | + if err := read(&indexOfPrevious); err != nil { | |
297 | + return nil, err | |
298 | + } | |
299 | + if err := read(&xofs); err != nil { | |
300 | + return nil, err | |
301 | + } | |
302 | + if err := read(&size); err != nil { | |
303 | + return nil, err | |
304 | + } | |
305 | + } | |
306 | + if s.rle != -12 { | |
307 | + f.Seek(int64(lofs+xofs), 0) | |
308 | + s.Pal = make([]uint32, 256) | |
309 | + var rgba [4]byte | |
310 | + for i := 0; i < int(size)/4 && i < len(s.Pal); i++ { | |
311 | + if err := read(rgba[:]); err != nil { | |
312 | + return nil, err | |
313 | + } | |
314 | + s.Pal[i] = uint32(rgba[2])<<16 | uint32(rgba[1])<<8 | uint32(rgba[0]) | |
315 | + } | |
316 | + } | |
317 | + s.palidx = -1 | |
318 | + return s, nil | |
319 | +} | |
309 | 320 | func (s *Sprite) shareCopy(src *Sprite) { |
310 | 321 | s.Pal = src.Pal |
311 | 322 | s.Tex = src.Tex |
@@ -475,7 +486,7 @@ func (s *Sprite) read(f *os.File, sh *SffHeader, offset int64, | ||
475 | 486 | if err := read(rgb[:]); err != nil { |
476 | 487 | return err |
477 | 488 | } |
478 | - pal[i] = uint32(rgb[0])<<16 | uint32(rgb[1])<<16 | uint32(rgb[2]) | |
489 | + pal[i] = uint32(rgb[2])<<16 | uint32(rgb[1])<<8 | uint32(rgb[0]) | |
479 | 490 | } |
480 | 491 | } |
481 | 492 | s.SetPxl(s.RlePcxDecode(px)) |
@@ -677,8 +688,7 @@ func (s *Sprite) Lz5Decode(rle []byte) (p []byte) { | ||
677 | 688 | } |
678 | 689 | return |
679 | 690 | } |
680 | -func (s *Sprite) readV2(f *os.File, sh *SffHeader, offset int64, | |
681 | - datasize uint32) error { | |
691 | +func (s *Sprite) readV2(f *os.File, offset int64, datasize uint32) error { | |
682 | 692 | f.Seek(offset+4, 0) |
683 | 693 | if s.rle < 0 { |
684 | 694 | format := -s.rle |
@@ -689,6 +699,36 @@ func (s *Sprite) readV2(f *os.File, sh *SffHeader, offset int64, | ||
689 | 699 | return err |
690 | 700 | } |
691 | 701 | } |
702 | + getIHDR := func() (png_ptr C.png_structp, info_ptr C.png_infop, | |
703 | + width, height C.png_uint_32, bit_depth, color_type C.int, | |
704 | + ok bool, err error) { | |
705 | + png_sig := make([]C.png_byte, 8) | |
706 | + if err = binary.Read(f, binary.LittleEndian, png_sig); err != nil { | |
707 | + return | |
708 | + } | |
709 | + if C.png_sig_cmp(&png_sig[0], 0, 8) != 0 { | |
710 | + err = Error("png_sig_cmp failed") | |
711 | + return | |
712 | + } | |
713 | + png_ptr = C.png_create_read_struct(C.CString(C.PNG_LIBPNG_VER_STRING), | |
714 | + nil, nil, nil) | |
715 | + if png_ptr == nil { | |
716 | + err = Error("png_create_read_struct failed") | |
717 | + return | |
718 | + } | |
719 | + info_ptr = C.png_create_info_struct(png_ptr) | |
720 | + if info_ptr == nil { | |
721 | + C.png_destroy_read_struct(&png_ptr, nil, nil) | |
722 | + err = Error("png_create_info_struct failed") | |
723 | + return | |
724 | + } | |
725 | + C.png_init_io(png_ptr, C.fdopen(C.int(f.Fd()), C.CString("rb"))) | |
726 | + C.png_set_sig_bytes(png_ptr, 8) | |
727 | + C.png_read_info(png_ptr, info_ptr) | |
728 | + ok = C.png_get_IHDR(png_ptr, info_ptr, &width, &height, | |
729 | + &bit_depth, &color_type, nil, nil, nil) != 0 | |
730 | + return | |
731 | + } | |
692 | 732 | switch format { |
693 | 733 | case 2: |
694 | 734 | px = s.Rle8Decode(px) |
@@ -697,14 +737,75 @@ func (s *Sprite) readV2(f *os.File, sh *SffHeader, offset int64, | ||
697 | 737 | case 4: |
698 | 738 | px = s.Lz5Decode(px) |
699 | 739 | case 10: |
740 | + png_ptr, info_ptr, width, height, bit_depth, color_type, ok, err := | |
741 | + getIHDR() | |
742 | + if err != nil { | |
743 | + return err | |
744 | + } | |
745 | + if ok && color_type == C.PNG_COLOR_TYPE_PALETTE && bit_depth <= 8 { | |
746 | + px = make([]byte, int(width*height)) | |
747 | + pp := make([]*C.png_byte, int(height)) | |
748 | + for i := range pp { | |
749 | + pp[i] = (*C.png_byte)(&px[i*int(width)]) | |
750 | + } | |
751 | + C.png_read_image(png_ptr, &pp[0]) | |
752 | + switch bit_depth { | |
753 | + case 1: | |
754 | + for y := range pp { | |
755 | + for i := width - 1; i >= 0; i-- { | |
756 | + p := (*[1 << 30]byte)(unsafe.Pointer(pp[y]))[:width:width] | |
757 | + p[i] = p[i>>3] & (1 << uint(i&7)) >> uint(i&7) | |
758 | + } | |
759 | + } | |
760 | + case 2: | |
761 | + for y := range pp { | |
762 | + for i := width - 1; i >= 0; i-- { | |
763 | + p := (*[1 << 30]byte)(unsafe.Pointer(pp[y]))[:width:width] | |
764 | + p[i] = p[i>>2] & (3 << uint(i&3*2)) >> uint(i&3*2) | |
765 | + } | |
766 | + } | |
767 | + case 4: | |
768 | + for y := range pp { | |
769 | + for i := width - 1; i >= 0; i-- { | |
770 | + p := (*[1 << 30]byte)(unsafe.Pointer(pp[y]))[:width:width] | |
771 | + p[i] = p[i>>1] & (15 << uint(i&1*4)) >> uint(i&1*4) | |
772 | + } | |
773 | + } | |
774 | + } | |
775 | + } | |
776 | + C.png_destroy_read_struct(&png_ptr, &info_ptr, nil) | |
700 | 777 | case 11, 12: |
701 | 778 | s.rle = -12 |
702 | - img, err := png.Decode(f) | |
779 | + png_ptr, info_ptr, width, height, bit_depth, color_type, ok, err := | |
780 | + getIHDR() | |
703 | 781 | if err != nil { |
704 | 782 | return err |
705 | 783 | } |
706 | - s.Tex = NewTexture() | |
707 | - s.Tex.FromImage(img) | |
784 | + if ok { | |
785 | + if bit_depth > 8 { | |
786 | + C.png_set_strip_16(png_ptr) | |
787 | + } | |
788 | + C.png_set_expand(png_ptr) | |
789 | + if color_type&C.PNG_COLOR_MASK_ALPHA == 0 { | |
790 | + C.png_set_add_alpha(png_ptr, 0xFF, C.PNG_FILLER_AFTER) | |
791 | + } | |
792 | + px = make([]byte, int(width*height*4)) | |
793 | + pp := make([]*C.png_byte, int(height)) | |
794 | + for i := range pp { | |
795 | + pp[i] = (*C.png_byte)(&px[i*int(width)*4]) | |
796 | + } | |
797 | + C.png_read_image(png_ptr, &pp[0]) | |
798 | + s.Tex = NewTexture() | |
799 | + gl.BindTexture(gl.TEXTURE_2D, uint32(*s.Tex)) | |
800 | + gl.PixelStorei(gl.UNPACK_ALIGNMENT, 1) | |
801 | + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(width), int32(height), | |
802 | + 0, gl.RGBA, gl.UNSIGNED_BYTE, unsafe.Pointer(&px[0])) | |
803 | + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) | |
804 | + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) | |
805 | + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP) | |
806 | + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP) | |
807 | + } | |
808 | + C.png_destroy_read_struct(&png_ptr, &info_ptr, nil) | |
708 | 809 | return nil |
709 | 810 | default: |
710 | 811 | return Error("不明な形式です") |
@@ -713,3 +814,31 @@ func (s *Sprite) readV2(f *os.File, sh *SffHeader, offset int64, | ||
713 | 814 | } |
714 | 815 | return nil |
715 | 816 | } |
817 | +func (s *Sprite) glDraw(pal []uint32, mask int32, x, y float32, tile *[4]int32, | |
818 | + xts, xbs, ys, rxadd, agl float32, trans int32, window *[4]int32, | |
819 | + rcx, rcy float32, fx *PalFX) { | |
820 | + if s.Tex == nil { | |
821 | + return | |
822 | + } | |
823 | + if s.rle == -12 { | |
824 | + neg, color, padd, pmul := fx.GetFcPalFx(trans) | |
825 | + RenderMugenFc(*s.Tex, s.Size, x, y, tile, xts, xbs, ys, 1, rxadd, agl, | |
826 | + trans, window, rcx, rcy, neg, color, &padd, &pmul) | |
827 | + } else { | |
828 | + RenderMugen(*s.Tex, pal, mask, s.Size, x, y, tile, xts, xbs, ys, 1, | |
829 | + rxadd, agl, trans, window, rcx, rcy) | |
830 | + } | |
831 | +} | |
832 | +func (s *Sprite) Draw(x, y, xscale, yscale float32, pal []uint32) { | |
833 | + x -= xscale*float32(s.Offset[0]) + float32(GameWidth-320)/2 | |
834 | + y -= yscale*float32(s.Offset[1]) + float32(GameHeight-240) | |
835 | + if xscale < 0 { | |
836 | + x *= -1 | |
837 | + } | |
838 | + if yscale < 0 { | |
839 | + y *= -1 | |
840 | + } | |
841 | + s.glDraw(pal, 0, -x*WidthScale, -y*HeightScale, ¬iling, | |
842 | + xscale*WidthScale, xscale*WidthScale, yscale*HeightScale, 0, 0, 255, | |
843 | + &scrrect, 0, 0, nil) | |
844 | +} |
@@ -9,10 +9,14 @@ import ( | ||
9 | 9 | "time" |
10 | 10 | ) |
11 | 11 | |
12 | +var windowWidth, windowHeight int32 = 640, 480 | |
13 | +var GameWidth, GameHeight int32 = 320, 240 | |
14 | +var WidthScale = float32(windowWidth) / float32(GameWidth) | |
15 | +var HeightScale = float32(windowHeight) / float32(GameHeight) | |
12 | 16 | var window *glfw.Window |
13 | -var windowWidth, windowHeight = 640, 480 | |
14 | 17 | var gameEnd, frameSkip = false, false |
15 | 18 | var redrawWait = struct{ nextTime, lastDraw time.Time }{} |
19 | +var testSprite *Sprite | |
16 | 20 | |
17 | 21 | func init() { |
18 | 22 | runtime.LockOSThread() |
@@ -49,9 +53,9 @@ func await(fps int) { | ||
49 | 53 | glfw.PollEvents() |
50 | 54 | gameEnd = window.ShouldClose() |
51 | 55 | if !frameSkip { |
52 | - windowWidth, windowHeight = window.GetFramebufferSize() | |
53 | 56 | gl.Viewport(0, 0, int32(windowWidth), int32(windowHeight)) |
54 | 57 | gl.Clear(gl.COLOR_BUFFER_BIT) |
58 | + testSprite.Draw(160, 120, 1, 1, testSprite.GetPal(nil)) | |
55 | 59 | } |
56 | 60 | } |
57 | 61 | func main() { |
@@ -61,15 +65,18 @@ func main() { | ||
61 | 65 | glfw.WindowHint(glfw.ContextVersionMajor, 2) |
62 | 66 | glfw.WindowHint(glfw.ContextVersionMinor, 1) |
63 | 67 | var err error |
64 | - window, err = | |
65 | - glfw.CreateWindow(windowWidth, windowHeight, "Ikemen GO", nil, nil) | |
68 | + window, err = glfw.CreateWindow(int(windowWidth), int(windowHeight), | |
69 | + "Ikemen GO", nil, nil) | |
66 | 70 | chk(err) |
67 | 71 | window.MakeContextCurrent() |
68 | - chk(gl.Init()) | |
69 | - gltest() | |
70 | 72 | glfw.SwapInterval(1) |
71 | - l := lua.NewState() | |
73 | + chk(gl.Init()) | |
74 | + RenderInit() | |
75 | + if testSprite, err = LoadFromSff("data/testv2.sff", 0, 0); err != nil { | |
76 | + panic(err) | |
77 | + } | |
72 | 78 | audioOpen() |
79 | + l := lua.NewState() | |
73 | 80 | lua.OpenLibraries(l) |
74 | 81 | systemScriptInit(l) |
75 | 82 | if err := lua.DoFile(l, "script/main.lua"); err != nil { |
@@ -0,0 +1,449 @@ | ||
1 | +package main | |
2 | + | |
3 | +import ( | |
4 | + "github.com/go-gl/gl/v2.1/gl" | |
5 | + "math" | |
6 | + "strings" | |
7 | + "unsafe" | |
8 | +) | |
9 | + | |
10 | +var notiling = [4]int32{0, 0, 0, 0} | |
11 | +var scrrect = [4]int32{0, 0, int32(windowWidth), int32(windowHeight)} | |
12 | +var mugenShader uintptr | |
13 | +var uniformA, uniformPal, uniformMsk int32 | |
14 | +var mugenShaderFc uintptr | |
15 | +var uniformFcA, uniformNeg, uniformGray, uniformAdd, uniformMul int32 | |
16 | +var mugenShaderFcS uintptr | |
17 | +var uniformFcSA, uniformColor int32 | |
18 | + | |
19 | +func RenderInit() { | |
20 | + vertShader := strings.Join([]string{ | |
21 | + "void main(void){", | |
22 | + "gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;", | |
23 | + "gl_Position = ftransform();", | |
24 | + "}\x00"}, "") | |
25 | + fragShader := strings.Join([]string{ | |
26 | + "uniform float a;", | |
27 | + "uniform sampler2D tex;", | |
28 | + "uniform sampler1D pal;", | |
29 | + "uniform int msk;", | |
30 | + "void main(void){", | |
31 | + "float r = texture2D(tex, gl_TexCoord[0].st).r;", | |
32 | + "vec4 c;", | |
33 | + "gl_FragColor =", | |
34 | + "int(255.0*r) == msk ? vec4(0.0)", | |
35 | + ": (c = texture1D(pal, r*0.9961), vec4(c.rgb, a));", | |
36 | + "}\x00"}, "") | |
37 | + fragShaderFc := strings.Join([]string{ | |
38 | + "uniform float a;", | |
39 | + "uniform sampler2D tex;", | |
40 | + "uniform bool neg;", | |
41 | + "uniform float gray;", | |
42 | + "uniform vec3 add;", | |
43 | + "uniform vec3 mul;", | |
44 | + "void main(void){", | |
45 | + "vec4 c = texture2D(tex, gl_TexCoord[0].st);", | |
46 | + "if(neg) c.rgb = vec3(1.0) - c.rgb;", | |
47 | + "float gcol = (c.r + c.g + c.b) / 3.0;", | |
48 | + "c.r += (gcol - c.r) * gray + add.r;", | |
49 | + "c.g += (gcol - c.g) * gray + add.g;", | |
50 | + "c.b += (gcol - c.b) * gray + add.b;", | |
51 | + "c.rgb *= mul;", | |
52 | + "c.a *= a;", | |
53 | + "gl_FragColor = c;", | |
54 | + "}\x00"}, "") | |
55 | + fragShaderFcS := strings.Join([]string{ | |
56 | + "uniform float a;", | |
57 | + "uniform sampler2D tex;", | |
58 | + "uniform vec3 color;", | |
59 | + "void main(void){", | |
60 | + "vec4 c = texture2D(tex, gl_TexCoord[0].st);", | |
61 | + "c.rgb = color * c.a;", | |
62 | + "c.a *= a;", | |
63 | + "gl_FragColor = c;", | |
64 | + "}\x00"}, "") | |
65 | + errLog := func(obl uintptr) error { | |
66 | + var size int32 | |
67 | + gl.GetObjectParameterivARB(obl, gl.INFO_LOG_LENGTH, &size) | |
68 | + if size <= 0 { | |
69 | + return nil | |
70 | + } | |
71 | + var l int32 | |
72 | + str := make([]byte, size+1) | |
73 | + gl.GetInfoLogARB(obl, size, &l, &str[0]) | |
74 | + return Error(str[:l]) | |
75 | + } | |
76 | + compile := func(shaderType uint32, src string) (shader uintptr) { | |
77 | + shader = gl.CreateShaderObjectARB(shaderType) | |
78 | + s, l := gl.Str(src), int32(len(src)-1) | |
79 | + gl.ShaderSourceARB(shader, 1, &s, &l) | |
80 | + gl.CompileShaderARB(shader) | |
81 | + var ok int32 | |
82 | + gl.GetObjectParameterivARB(shader, gl.OBJECT_COMPILE_STATUS_ARB, &ok) | |
83 | + if ok == 0 { | |
84 | + chk(errLog(shader)) | |
85 | + panic(Error("コンパイルエラー")) | |
86 | + } | |
87 | + return | |
88 | + } | |
89 | + link := func(v uintptr, f uintptr) (program uintptr) { | |
90 | + program = gl.CreateProgramObjectARB() | |
91 | + gl.AttachObjectARB(program, v) | |
92 | + gl.AttachObjectARB(program, f) | |
93 | + gl.LinkProgramARB(program) | |
94 | + var ok int32 | |
95 | + gl.GetObjectParameterivARB(program, gl.OBJECT_LINK_STATUS_ARB, &ok) | |
96 | + if ok == 0 { | |
97 | + chk(errLog(program)) | |
98 | + panic(Error("リンクエラー")) | |
99 | + } | |
100 | + return | |
101 | + } | |
102 | + vertObj := compile(gl.VERTEX_SHADER, vertShader) | |
103 | + fragObj := compile(gl.FRAGMENT_SHADER, fragShader) | |
104 | + mugenShader = link(vertObj, fragObj) | |
105 | + uniformA = gl.GetUniformLocationARB(mugenShader, gl.Str("a\x00")) | |
106 | + uniformPal = gl.GetUniformLocationARB(mugenShader, gl.Str("pal\x00")) | |
107 | + uniformMsk = gl.GetUniformLocationARB(mugenShader, gl.Str("msk\x00")) | |
108 | + gl.DeleteObjectARB(fragObj) | |
109 | + fragObj = compile(gl.FRAGMENT_SHADER, fragShaderFc) | |
110 | + mugenShaderFc = link(vertObj, fragObj) | |
111 | + uniformFcA = gl.GetUniformLocationARB(mugenShader, gl.Str("a\x00")) | |
112 | + uniformNeg = gl.GetUniformLocationARB(mugenShaderFc, gl.Str("neg\x00")) | |
113 | + uniformGray = gl.GetUniformLocationARB(mugenShaderFc, gl.Str("gray\x00")) | |
114 | + uniformAdd = gl.GetUniformLocationARB(mugenShaderFc, gl.Str("add\x00")) | |
115 | + uniformMul = gl.GetUniformLocationARB(mugenShaderFc, gl.Str("mul\x00")) | |
116 | + gl.DeleteObjectARB(fragObj) | |
117 | + fragObj = compile(gl.FRAGMENT_SHADER, fragShaderFcS) | |
118 | + mugenShaderFcS = link(vertObj, fragObj) | |
119 | + uniformFcSA = gl.GetUniformLocationARB(mugenShader, gl.Str("a\x00")) | |
120 | + uniformColor = gl.GetUniformLocationARB(mugenShaderFcS, gl.Str("color\x00")) | |
121 | + gl.DeleteObjectARB(fragObj) | |
122 | + gl.DeleteObjectARB(vertObj) | |
123 | + scrrect[2], scrrect[3] = int32(windowWidth), int32(windowHeight) | |
124 | +} | |
125 | +func kaiten(x *float32, y *float32, | |
126 | + angle float64, rcx float32, rcy float32, vscl float32) { | |
127 | + temp := (*y - rcy) / vscl | |
128 | + length := math.Sqrt(float64((*x-rcx)*(*x-rcx) + temp*temp)) | |
129 | + if *x-rcx == 0 { | |
130 | + if *y-rcy > 0 { | |
131 | + angle += math.Pi / 2 | |
132 | + } else { | |
133 | + angle -= math.Pi / 2 | |
134 | + } | |
135 | + *x = rcx + float32(length*math.Cos(angle)) | |
136 | + *y = rcy + float32(length*math.Sin(angle))*vscl | |
137 | + return | |
138 | + } | |
139 | + kakudo := math.Atan(float64(temp/(*x-rcx))) + angle | |
140 | + if *x-rcx < 0 { | |
141 | + kakudo += math.Pi | |
142 | + } | |
143 | + *x = rcx + float32(length*math.Cos(kakudo)) | |
144 | + *y = rcy + float32(length*math.Sin(kakudo))*vscl | |
145 | +} | |
146 | +func drawQuads(x1, y1, x2, y2, x3, y3, x4, y4, r, g, b, a, pers float32) { | |
147 | + gl.Color4f(r, g, b, a) | |
148 | + gl.Begin(gl.TRIANGLE_STRIP) | |
149 | + gl.TexCoord2f(0, 1) | |
150 | + gl.Vertex2f(x1, y1) | |
151 | + gl.TexCoord2f(0, 0) | |
152 | + gl.Vertex2f(x4, y4) | |
153 | + if pers != 1 { | |
154 | + n := int((1 - (pers * pers)) * Abs(x1-x2) * | |
155 | + float32(windowHeight>>5) / (Abs(y1-y4) + float32(windowHeight>>5))) | |
156 | + for i := 1; i < n; i++ { | |
157 | + gl.TexCoord2f(float32(i)/float32(n), 1) | |
158 | + gl.Vertex2f(x1+(x2-x1)*float32(i)/float32(n), | |
159 | + y1+(y2-y1)*float32(i)/float32(n)) | |
160 | + gl.TexCoord2f(float32(i)/float32(n), 0) | |
161 | + gl.Vertex2f(x4+(x3-x4)*float32(i)/float32(n), | |
162 | + y4+(y3-y4)*float32(i)/float32(n)) | |
163 | + } | |
164 | + } | |
165 | + gl.TexCoord2f(1, 1) | |
166 | + gl.Vertex2f(x2, y2) | |
167 | + gl.TexCoord2f(1, 0) | |
168 | + gl.Vertex2f(x3, y3) | |
169 | + gl.End() | |
170 | +} | |
171 | +func rmTileHSub(x1, y1, x2, y2, x3, y3, x4, y4, xtw, xbw, xts, xbs float32, | |
172 | + tl *[4]int32, rcx, r, g, b, a, pers float32) { | |
173 | + topdist := xtw + xts*float32((*tl)[0]) | |
174 | + if Abs(topdist) >= 0.01 { | |
175 | + botdist := xbw + xbs*float32((*tl)[0]) | |
176 | + db := (x4 - rcx) * (botdist - topdist) / Abs(topdist) | |
177 | + x1 += db | |
178 | + x2 += db | |
179 | + if (*tl)[2] == 1 { | |
180 | + x1d, x2d, x3d, x4d := x1, x2, x3, x4 | |
181 | + for { | |
182 | + x2d = x1d - xbs*float32((*tl)[0]) | |
183 | + x3d = x4d - xts*float32((*tl)[0]) | |
184 | + x4d = x3d - xtw | |
185 | + x1d = x2d - xbw | |
186 | + if topdist < 0 { | |
187 | + if x1d >= float32(windowWidth) && x2d >= float32(windowWidth) && | |
188 | + x3d >= float32(windowWidth) && x4d >= float32(windowWidth) { | |
189 | + break | |
190 | + } | |
191 | + } else if x1d <= 0 && x2d <= 0 && x3d <= 0 && x4d <= 0 { | |
192 | + break | |
193 | + } | |
194 | + if (0 < x1d || 0 < x2d) && | |
195 | + (x1d < float32(windowWidth) || x2d < float32(windowWidth)) || | |
196 | + (0 < x3d || 0 < x4d) && | |
197 | + (x3d < float32(windowWidth) || x4d < float32(windowWidth)) { | |
198 | + drawQuads(x1d, y1, x2d, y2, x3d, y3, x4d, y4, r, g, b, a, pers) | |
199 | + } | |
200 | + } | |
201 | + } | |
202 | + } | |
203 | + n := (*tl)[2] | |
204 | + for { | |
205 | + if topdist > 0 { | |
206 | + if x1 >= float32(windowWidth) && x2 >= float32(windowWidth) && | |
207 | + x3 >= float32(windowWidth) && x4 >= float32(windowWidth) { | |
208 | + break | |
209 | + } | |
210 | + } else if x1 <= 0 && x2 <= 0 && x3 <= 0 && x4 <= 0 { | |
211 | + break | |
212 | + } | |
213 | + if (0 < x1 || 0 < x2) && | |
214 | + (x1 < float32(windowWidth) || x2 < float32(windowWidth)) || | |
215 | + (0 < x3 || 0 < x4) && | |
216 | + (x3 < float32(windowWidth) || x4 < float32(windowWidth)) { | |
217 | + drawQuads(x1, y1, x2, y2, x3, y3, x4, y4, r, g, b, a, pers) | |
218 | + } | |
219 | + if (*tl)[2] != 1 && n != 0 { | |
220 | + n-- | |
221 | + } | |
222 | + if n == 0 || Abs(topdist) < 0.01 { | |
223 | + break | |
224 | + } | |
225 | + x4 = x3 + xts*float32((*tl)[0]) | |
226 | + x1 = x2 + xbs*float32((*tl)[0]) | |
227 | + x2 = x1 + xbw | |
228 | + x3 = x4 + xtw | |
229 | + } | |
230 | +} | |
231 | +func rmTileSub(w, h uint16, x, y float32, tl *[4]int32, | |
232 | + xts, xbs, ys, vs, rxadd, agl, rcx, rcy, r, g, b, a float32) { | |
233 | + x1, y1 := x+rxadd*ys*float32(h), rcy+((y-ys*float32(h))-rcy)*vs | |
234 | + x2, y2 := x1+xbs*float32(w), y1 | |
235 | + x3, y3 := x+xts*float32(w), rcy+(y-rcy)*vs | |
236 | + x4, y4 := x, y3 | |
237 | + var pers float32 | |
238 | + if Abs(xts) < Abs(xbs) { | |
239 | + pers = Abs(xts) / Abs(xbs) | |
240 | + } else { | |
241 | + pers = Abs(xbs) / Abs(xts) | |
242 | + } | |
243 | + if agl != 0 { | |
244 | + kaiten(&x1, &y1, float64(agl), rcx, rcy, vs) | |
245 | + kaiten(&x2, &y2, float64(agl), rcx, rcy, vs) | |
246 | + kaiten(&x3, &y3, float64(agl), rcx, rcy, vs) | |
247 | + kaiten(&x4, &y4, float64(agl), rcx, rcy, vs) | |
248 | + drawQuads(x1, y1, x2, y2, x3, y3, x4, y4, r, g, b, a, pers) | |
249 | + return | |
250 | + } | |
251 | + if (*tl)[3] == 1 && xbs != 0 { | |
252 | + x1d, y1d, x2d, y2d, x3d, y3d, x4d, y4d := x1, y1, x2, y2, x3, y3, x4, y4 | |
253 | + for { | |
254 | + x1d, y1d = x4d, y4d+ys*vs*float32((*tl)[1]) | |
255 | + x2d, y2d = x3d, y1d | |
256 | + x3d = x4d - rxadd*ys*float32(h) + (xts/xbs)*(x3d-x4d) | |
257 | + y3d = y2d + ys*vs*float32(h) | |
258 | + x4d = x4d - rxadd*ys*float32(h) | |
259 | + if Abs(y3d-y4d) < 0.01 { | |
260 | + break | |
261 | + } | |
262 | + y4d = y3d | |
263 | + if ys*(float32(h)+float32((*tl)[1])) < 0 { | |
264 | + if y1d <= float32(-windowHeight) && y4d <= float32(-windowHeight) { | |
265 | + break | |
266 | + } | |
267 | + } else if y1d >= 0 && y4d >= 0 { | |
268 | + break | |
269 | + } | |
270 | + if (0 > y1d || 0 > y4d) && | |
271 | + (y1d > float32(-windowHeight) || y4d > float32(-windowHeight)) { | |
272 | + rmTileHSub(x1d, y1d, x2d, y2d, x3d, y3d, x4d, y4d, x3d-x4d, x2d-x1d, | |
273 | + (x3d-x4d)/float32(w), (x2d-x1d)/float32(w), tl, | |
274 | + rcx, r, g, b, a, pers) | |
275 | + } | |
276 | + } | |
277 | + } | |
278 | + if (*tl)[3] == 0 || xts != 0 { | |
279 | + n := (*tl)[3] | |
280 | + for { | |
281 | + if ys*(float32(h)+float32((*tl)[1])) > 0 { | |
282 | + if y1 <= float32(-windowHeight) && y4 <= float32(-windowHeight) { | |
283 | + break | |
284 | + } | |
285 | + } else if y1 >= 0 && y4 >= 0 { | |
286 | + break | |
287 | + } | |
288 | + if (0 > y1 || 0 > y4) && | |
289 | + (y1 > float32(-windowHeight) || y4 > float32(-windowHeight)) { | |
290 | + rmTileHSub(x1, y1, x2, y2, x3, y3, x4, y4, x3-x4, x2-x1, | |
291 | + (x3-x4)/float32(w), (x2-x1)/float32(w), tl, rcx, r, g, b, a, pers) | |
292 | + } | |
293 | + if (*tl)[3] != 1 && n != 0 { | |
294 | + n-- | |
295 | + } | |
296 | + if n == 0 { | |
297 | + break | |
298 | + } | |
299 | + x4, y4 = x1, y1-ys*vs*float32((*tl)[1]) | |
300 | + x3, y3 = x2, y4 | |
301 | + x2 = x1 + rxadd*ys*float32(h) + (xbs/xts)*(x2-x1) | |
302 | + y2 = y3 - ys*vs*float32(h) | |
303 | + x1 = x1 + rxadd*ys*float32(h) | |
304 | + if Abs(y1-y2) < 0.01 { | |
305 | + break | |
306 | + } | |
307 | + y1 = y2 | |
308 | + } | |
309 | + } | |
310 | +} | |
311 | +func rmMainSub(a int32, size [2]uint16, x, y float32, tl *[4]int32, | |
312 | + xts, xbs, ys, vs, rxadd, agl float32, trans int32, rcx, rcy float32) { | |
313 | + gl.MatrixMode(gl.PROJECTION) | |
314 | + gl.PushMatrix() | |
315 | + gl.LoadIdentity() | |
316 | + gl.Ortho(0, float64(windowWidth), 0, float64(windowHeight), -1, 1) | |
317 | + gl.MatrixMode(gl.MODELVIEW) | |
318 | + gl.PushMatrix() | |
319 | + gl.Translated(0, float64(windowHeight), 0) | |
320 | + switch { | |
321 | + case trans == -1: | |
322 | + gl.Uniform1fARB(a, 1) | |
323 | + gl.BlendFunc(gl.SRC_ALPHA, gl.ONE) | |
324 | + rmTileSub(size[0], size[1], x, y, tl, xts, xbs, ys, vs, rxadd, | |
325 | + agl, rcx, rcy, 1, 1, 1, 1) | |
326 | + case trans == -2: | |
327 | + gl.Uniform1fARB(a, 1) | |
328 | + gl.BlendFunc(gl.ZERO, gl.ONE_MINUS_SRC_COLOR) | |
329 | + rmTileSub(size[0], size[1], x, y, tl, xts, xbs, ys, vs, rxadd, | |
330 | + agl, rcx, rcy, 1, 1, 1, 1) | |
331 | + case trans <= 0: | |
332 | + case trans < 255: | |
333 | + gl.Uniform1fARB(a, float32(trans)/255) | |
334 | + gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) | |
335 | + rmTileSub(size[0], size[1], x, y, tl, xts, xbs, ys, vs, rxadd, | |
336 | + agl, rcx, rcy, 1, 1, 1, float32(trans)/255) | |
337 | + case trans < 512: | |
338 | + gl.Uniform1fARB(a, 1) | |
339 | + gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) | |
340 | + rmTileSub(size[0], size[1], x, y, tl, xts, xbs, ys, vs, rxadd, | |
341 | + agl, rcx, rcy, 1, 1, 1, 1) | |
342 | + default: | |
343 | + src, dst := trans&0xff, trans&0x3fc00>>10 | |
344 | + if dst < 255 { | |
345 | + gl.Uniform1fARB(a, 1-float32(dst)/255) | |
346 | + gl.BlendFunc(gl.ZERO, gl.ONE_MINUS_SRC_ALPHA) | |
347 | + rmTileSub(size[0], size[1], x, y, tl, xts, xbs, ys, vs, rxadd, | |
348 | + agl, rcx, rcy, 1, 1, 1, 1-float32(trans)/255) | |
349 | + } | |
350 | + if src > 0 { | |
351 | + gl.Uniform1fARB(a, float32(src)/255) | |
352 | + gl.BlendFunc(gl.SRC_ALPHA, gl.ONE) | |
353 | + rmTileSub(size[0], size[1], x, y, tl, xts, xbs, ys, vs, rxadd, | |
354 | + agl, rcx, rcy, 1, 1, 1, float32(trans)/255) | |
355 | + } | |
356 | + } | |
357 | + gl.PopMatrix() | |
358 | + gl.MatrixMode(gl.PROJECTION) | |
359 | + gl.PopMatrix() | |
360 | +} | |
361 | +func rmInitSub(size [2]uint16, x, y *float32, tile *[4]int32, xts float32, | |
362 | + ys, vs, agl *float32, window *[4]int32, rcx float32, rcy *float32) ( | |
363 | + tl [4]int32) { | |
364 | + if *vs < 0 { | |
365 | + *vs *= -1 | |
366 | + *ys *= -1 | |
367 | + *agl *= -1 | |
368 | + } | |
369 | + tl = *tile | |
370 | + if tl[2] == 0 { | |
371 | + tl[0] = 0 | |
372 | + } else if tl[0] > 0 { | |
373 | + tl[0] -= int32(size[0]) | |
374 | + } | |
375 | + if tl[3] == 0 { | |
376 | + tl[1] = 0 | |
377 | + } else if tl[1] > 0 { | |
378 | + tl[1] -= int32(size[1]) | |
379 | + } | |
380 | + if xts >= 0 { | |
381 | + *x *= -1 | |
382 | + } | |
383 | + *x += rcx | |
384 | + *rcy *= -1 | |
385 | + if *ys < 0 { | |
386 | + *y *= -1 | |
387 | + } | |
388 | + *y += *rcy | |
389 | + gl.Enable(gl.TEXTURE_2D) | |
390 | + gl.Disable(gl.DEPTH_TEST) | |
391 | + gl.Enable(gl.SCISSOR_TEST) | |
392 | + gl.Scissor((*window)[0], windowHeight-((*window)[1]+(*window)[3]), | |
393 | + (*window)[2], (*window)[3]) | |
394 | + return | |
395 | +} | |
396 | +func RenderMugen(tex Texture, pal []uint32, mask int32, size [2]uint16, | |
397 | + x, y float32, tile *[4]int32, xts, xbs, ys, vs, rxadd, agl float32, | |
398 | + trans int32, window *[4]int32, rcx, rcy float32) { | |
399 | + if tex == 0 || !IsFinite(x+y+xts+xbs+ys+vs+rxadd+agl+rcx+rcy) { | |
400 | + return | |
401 | + } | |
402 | + tl := rmInitSub(size, &x, &y, tile, xts, &ys, &vs, &agl, window, rcx, &rcy) | |
403 | + gl.Enable(gl.TEXTURE_1D) | |
404 | + gl.UseProgramObjectARB(mugenShader) | |
405 | + gl.Uniform1iARB(uniformPal, 1) | |
406 | + gl.Uniform1iARB(uniformMsk, mask) | |
407 | + gl.ActiveTexture(gl.TEXTURE1) | |
408 | + var paltex uint32 | |
409 | + gl.GenTextures(1, &paltex) | |
410 | + gl.BindTexture(gl.TEXTURE_1D, paltex) | |
411 | + gl.PixelStorei(gl.UNPACK_ALIGNMENT, 1) | |
412 | + gl.TexImage1D(gl.TEXTURE_1D, 0, gl.RGBA, 256, 0, gl.RGBA, gl.UNSIGNED_BYTE, | |
413 | + unsafe.Pointer(&pal[0])) | |
414 | + gl.TexParameteri(gl.TEXTURE_1D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) | |
415 | + gl.TexParameteri(gl.TEXTURE_1D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) | |
416 | + gl.ActiveTexture(gl.TEXTURE0) | |
417 | + gl.BindTexture(gl.TEXTURE_2D, uint32(tex)) | |
418 | + rmMainSub(uniformA, size, x, y, &tl, xts, xbs, ys, vs, rxadd, agl, | |
419 | + trans, rcx, rcy) | |
420 | + gl.DeleteTextures(1, &paltex) | |
421 | + gl.UseProgramObjectARB(0) | |
422 | + gl.Disable(gl.TEXTURE_1D) | |
423 | + gl.Disable(gl.SCISSOR_TEST) | |
424 | + gl.Disable(gl.TEXTURE_2D) | |
425 | +} | |
426 | +func RenderMugenFc(tex Texture, size [2]uint16, x, y float32, | |
427 | + tile *[4]int32, xts, xbs, ys, vs, rxadd, agl float32, trans int32, | |
428 | + window *[4]int32, rcx, rcy float32, neg bool, color float32, | |
429 | + padd, pmul *[3]float32) { | |
430 | + if tex == 0 || !IsFinite(x+y+xts+xbs+ys+vs+rxadd+agl+rcx+rcy) { | |
431 | + return | |
432 | + } | |
433 | + tl := rmInitSub(size, &x, &y, tile, xts, &ys, &vs, &agl, window, rcx, &rcy) | |
434 | + gl.UseProgramObjectARB(mugenShaderFc) | |
435 | + ineg := int32(0) | |
436 | + if neg { | |
437 | + ineg = 1 | |
438 | + } | |
439 | + gl.Uniform1iARB(uniformNeg, ineg) | |
440 | + gl.Uniform1fARB(uniformGray, 1-color) | |
441 | + gl.Uniform3fARB(uniformAdd, (*padd)[0], (*padd)[1], (*padd)[2]) | |
442 | + gl.Uniform3fARB(uniformMul, (*pmul)[0], (*pmul)[1], (*pmul)[2]) | |
443 | + gl.BindTexture(gl.TEXTURE_2D, uint32(tex)) | |
444 | + rmMainSub(uniformFcA, size, x, y, &tl, xts, xbs, ys, vs, rxadd, agl, | |
445 | + trans, rcx, rcy) | |
446 | + gl.UseProgramObjectARB(0) | |
447 | + gl.Disable(gl.SCISSOR_TEST) | |
448 | + gl.Disable(gl.TEXTURE_2D) | |
449 | +} |