aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/vlib/gg/image.c.v
blob: 352eac4170c494a258e3413a5e39bad7eee8cf16 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
module gg

import os
import stbi
import sokol.gfx

fn C.sg_isvalid() bool

// TODO return ?Image
pub fn (mut ctx Context) create_image(file string) Image {
	// println('\ncreate_image("$file")')
	if !os.exists(file) {
		return Image{}
	}
	$if macos {
		if ctx.native_rendering {
			// return C.darwin_create_image(file)
			mut img := C.darwin_create_image(file)
			// println('created macos image: $img.path w=$img.width')
			// C.printf('p = %p\n', img.data)
			img.id = ctx.image_cache.len
			ctx.image_cache << img
			return img
		}
	}
	if !C.sg_isvalid() {
		// Sokol is not initialized yet, add stbi object to a queue/cache
		// ctx.image_queue << file
		stb_img := stbi.load(file) or { return Image{} }
		img := Image{
			width: stb_img.width
			height: stb_img.height
			nr_channels: stb_img.nr_channels
			ok: false
			data: stb_img.data
			ext: stb_img.ext
			path: file
			id: ctx.image_cache.len
		}
		ctx.image_cache << img
		return img
	}
	mut img := create_image(file)
	img.id = ctx.image_cache.len
	ctx.image_cache << img
	return img
}

pub fn (mut img Image) init_sokol_image() &Image {
	// println('\n init sokol image $img.path ok=$img.simg_ok')
	mut img_desc := C.sg_image_desc{
		width: img.width
		height: img.height
		num_mipmaps: 0
		wrap_u: .clamp_to_edge
		wrap_v: .clamp_to_edge
		label: img.path.str
		d3d11_texture: 0
	}
	img_desc.data.subimage[0][0] = C.sg_range{
		ptr: img.data
		size: size_t(img.nr_channels * img.width * img.height)
	}
	img.simg = C.sg_make_image(&img_desc)
	img.simg_ok = true
	img.ok = true
	return img
}

// draw_image draws the provided image onto the screen
pub fn (ctx &Context) draw_image(x f32, y f32, width f32, height f32, img_ &Image) {
	$if macos {
		if img_.id >= ctx.image_cache.len {
			eprintln('gg: draw_image() bad img id $img_.id (img cache len = $ctx.image_cache.len)')
			return
		}
		if ctx.native_rendering {
			if img_.width == 0 {
				return
			}
			if !os.exists(img_.path) {
				return
			}
			C.darwin_draw_image(x, ctx.height - (y + height), width, height, img_)
			return
		}
	}

	ctx.draw_image_with_config(
		img: img_
		img_rect: Rect{x, y, width, height}
		part_rect: Rect{0, 0, img_.width, img_.height}
	)
}

// new_streaming_image returns a cached `image_idx` of a special image, that
// can be updated *each frame* by calling:  gg.update_pixel_data(image_idx, buf)
// ... where buf is a pointer to the actual pixel data for the image.
// NB: you still need to call app.gg.draw_image after that, to actually draw it.
pub fn (mut ctx Context) new_streaming_image(w int, h int, channels int, sicfg StreamingImageConfig) int {
	mut img := Image{}
	img.width = w
	img.height = h
	img.nr_channels = channels // 4 bytes per pixel for .rgba8, see pixel_format
	mut img_desc := C.sg_image_desc{
		width: img.width
		height: img.height
		pixel_format: sicfg.pixel_format
		num_slices: 1
		num_mipmaps: 1
		usage: .stream
		wrap_u: sicfg.wrap_u
		wrap_v: sicfg.wrap_v
		min_filter: sicfg.min_filter
		mag_filter: sicfg.mag_filter
		label: img.path.str
	}
	// Sokol requires that streamed images have NO .ptr/.size initially:
	img_desc.data.subimage[0][0] = C.sg_range{
		ptr: 0
		size: size_t(0)
	}
	img.simg = C.sg_make_image(&img_desc)
	img.simg_ok = true
	img.ok = true
	img_idx := ctx.cache_image(img)
	return img_idx
}

// update_pixel_data is a helper for working with image streams (i.e. images,
// that are updated dynamically by the CPU on each frame)
pub fn (mut ctx Context) update_pixel_data(cached_image_idx int, buf &byte) {
	mut image := ctx.get_cached_image_by_idx(cached_image_idx)
	image.update_pixel_data(buf)
}

pub fn (mut img Image) update_pixel_data(buf &byte) {
	mut data := C.sg_image_data{}
	data.subimage[0][0].ptr = buf
	data.subimage[0][0].size = size_t(img.width * img.height * img.nr_channels)
	gfx.update_image(img.simg, &data)
}

// TODO copypasta
pub fn (mut ctx Context) create_image_with_size(file string, width int, height int) Image {
	if !C.sg_isvalid() {
		// Sokol is not initialized yet, add stbi object to a queue/cache
		// ctx.image_queue << file
		stb_img := stbi.load(file) or { return Image{} }
		img := Image{
			width: width
			height: height
			nr_channels: stb_img.nr_channels
			ok: false
			data: stb_img.data
			ext: stb_img.ext
			path: file
			id: ctx.image_cache.len
		}
		ctx.image_cache << img
		return img
	}
	mut img := create_image(file)
	img.id = ctx.image_cache.len
	ctx.image_cache << img
	return img
}