mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
Compare commits
2 commits
487feb9b0e
...
344f7ccdcb
Author | SHA1 | Date | |
---|---|---|---|
![]() |
344f7ccdcb | ||
![]() |
1e0bda4ebc |
6 changed files with 210 additions and 2 deletions
74
examples/gg/grid_of_rectangles.v
Normal file
74
examples/gg/grid_of_rectangles.v
Normal file
|
@ -0,0 +1,74 @@
|
|||
module main
|
||||
|
||||
import gg
|
||||
import sokol.sgl
|
||||
|
||||
struct App {
|
||||
mut:
|
||||
gg &gg.Context = unsafe { nil }
|
||||
}
|
||||
|
||||
const cmax_x = 115
|
||||
const cmax_y = 81
|
||||
const cs = 10
|
||||
|
||||
const c_fg = gg.rgb(20, 30, 255)
|
||||
const c_em = gg.rgb(255, 50, 0)
|
||||
|
||||
fn main() {
|
||||
mut app := &App{}
|
||||
app.gg = gg.new_context(
|
||||
bg_color: gg.white
|
||||
width: cmax_x * cs
|
||||
height: cmax_y * cs
|
||||
create_window: true
|
||||
window_title: 'Grid with many rectangles (drawn with no context)'
|
||||
frame_fn: frame
|
||||
user_data: app
|
||||
)
|
||||
app.gg.run()
|
||||
}
|
||||
|
||||
fn frame(app &App) {
|
||||
app.gg.begin()
|
||||
// Note: this uses 2 separate loops, with each doing its own drawing for performance reasons.
|
||||
// The underlying Sokol library can eliminate sgl begin/end calls, when multiple primitives of the
|
||||
// same kind are drawn one after the other, without context changes.
|
||||
// However, filled rectangles are drawn with quads, while empty rectangles are drawn with lines.
|
||||
// In this case, if the draw calls are put in the same loop, using app.gg.draw_rect_filled/5 and app.gg.draw_rect_empty/5,
|
||||
// sokol can not batch the begin/end calls, and their overhead becomes much bigger.
|
||||
//
|
||||
// That is why:
|
||||
// a) we use several loops here.
|
||||
// b) we use a single sgl.begin_quads() before the first loop, and a single sgl.end() after it.
|
||||
// c) we use draw_rect_filled_no_context/5 inside the loop, instead of draw_rect_filled/5 .
|
||||
// e) we use a single sgl.begin_lines() before the second loop, and a single sgl.end() after it.
|
||||
// f) we use draw_rect_empty_no_context/5 inside the second loop, instead of draw_rect_empty/5 .
|
||||
// Note: the separation of the loops/kinds of draws, is several times more important for eliminating
|
||||
// the performance overhead (12-15% CPU usage), compared to the use of draw_rect_filled_no_context
|
||||
// vs draw_rect_filled (1-2% CPU usage), because of Sokol's optimisation.
|
||||
|
||||
$if !do_not_draw_rect_filled ? {
|
||||
sgl.begin_quads()
|
||||
for y in 0 .. cmax_y {
|
||||
for x in 0 .. cmax_x {
|
||||
cy, cx := y * cs, x * cs
|
||||
app.gg.draw_rect_filled_no_context(cx, cy, cs - 2, cs - 2, c_fg)
|
||||
}
|
||||
}
|
||||
sgl.end()
|
||||
}
|
||||
|
||||
$if draw_rect_empty ? {
|
||||
sgl.begin_lines()
|
||||
for y in 0 .. cmax_y {
|
||||
for x in 0 .. cmax_x {
|
||||
cy, cx := y * cs, x * cs
|
||||
app.gg.draw_rect_empty_no_context(cx + 2, cy + 2, cs - 3, cs - 3, c_em)
|
||||
}
|
||||
}
|
||||
sgl.end()
|
||||
}
|
||||
|
||||
app.gg.end()
|
||||
}
|
|
@ -184,6 +184,8 @@ pub fn (ctx &Context) draw_convex_poly(points []f32, c Color) {
|
|||
// draw_rect_empty draws the outline of a rectangle.
|
||||
// `x`,`y` is the top-left corner of the rectangle.
|
||||
// `w` is the width, `h` is the height and `c` is the color of the outline.
|
||||
// Note: it is much more efficient to draw lots of empty rectangles one after the other,
|
||||
// without filled rectangles between them, than to draw a mix.
|
||||
pub fn (ctx &Context) draw_rect_empty(x f32, y f32, w f32, h f32, c Color) {
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.pipeline.alpha)
|
||||
|
@ -215,9 +217,48 @@ pub fn (ctx &Context) draw_rect_empty(x f32, y f32, w f32, h f32, c Color) {
|
|||
sgl.end()
|
||||
}
|
||||
|
||||
// draw_rect_empty_no_context draws the outline of a rectangle, but without saving/restoring the context.
|
||||
// It is intended to be used in loops, where you do manually: `sgl.begin_lines()` *before* the loop,
|
||||
// then draw many rectangles, then call manually `sgl.end()` *after* the loop.
|
||||
// `x`,`y` is the top-left corner of the rectangle.
|
||||
// `w` is the width, `h` is the height and `c` is the color of the outline.
|
||||
// Note: it is much more efficient to draw lots of empty rectangles one after the other,
|
||||
// without filled rectangles between them, than to draw a mix.
|
||||
pub fn (ctx &Context) draw_rect_empty_no_context(x f32, y f32, w f32, h f32, c Color) {
|
||||
// The small offsets here, are to make sure, that the start and end points will be
|
||||
// inside pixels, and not on their borders. That in turn, makes it much more likely
|
||||
// that different OpenGL implementations will render them identically, for example
|
||||
// Mesa, with `LIBGL_ALWAYS_SOFTWARE=1` renders the same as HD4000.
|
||||
mut toffset := f32(0.1)
|
||||
mut boffset := f32(-0.1)
|
||||
tleft_x := toffset + x * ctx.scale
|
||||
tleft_y := toffset + y * ctx.scale
|
||||
bright_x := boffset + (x + w) * ctx.scale
|
||||
bright_y := boffset + (y + h) * ctx.scale
|
||||
// Note: the following line is deliberately commented, compare to draw_rect_empty/5;
|
||||
// sgl.begin_lines() // more predictable, compared to sgl.begin_line_strip, at the price of more vertexes send
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
// top:
|
||||
sgl.v2f(tleft_x, tleft_y)
|
||||
sgl.v2f(bright_x, tleft_y)
|
||||
// left:
|
||||
sgl.v2f(tleft_x, tleft_y)
|
||||
sgl.v2f(tleft_x, bright_y)
|
||||
// right:
|
||||
sgl.v2f(bright_x, tleft_y)
|
||||
sgl.v2f(bright_x, bright_y)
|
||||
// bottom:
|
||||
sgl.v2f(tleft_x, bright_y)
|
||||
sgl.v2f(bright_x, bright_y)
|
||||
// Note: the following line is deliberately commented, compare to draw_rect_empty/5;
|
||||
// sgl.end()
|
||||
}
|
||||
|
||||
// draw_rect_filled draws a filled rectangle.
|
||||
// `x`,`y` is the top-left corner of the rectangle.
|
||||
// `w` is the width, `h` is the height and `c` is the color of the fill.
|
||||
// Note: it is much more efficient to draw lots of filled rectangles one after the other,
|
||||
// without empty rectangles between them, than to draw a mix.
|
||||
pub fn (ctx &Context) draw_rect_filled(x f32, y f32, w f32, h f32, c Color) {
|
||||
$if macos {
|
||||
if ctx.native_rendering {
|
||||
|
@ -239,6 +280,25 @@ pub fn (ctx &Context) draw_rect_filled(x f32, y f32, w f32, h f32, c Color) {
|
|||
sgl.end()
|
||||
}
|
||||
|
||||
// draw_rect_filled_no_context draws a filled rectangle, but without saving/restoring the context.
|
||||
// It is intended to be used in loops, where you do manually: `sgl.begin_quads()` *before* the loop,
|
||||
// then draw many rectangles, then call manually `sgl.end()` *after* the loop.
|
||||
// `x`,`y` is the top-left corner of the rectangle.
|
||||
// `w` is the width, `h` is the height and `c` is the color of the fill.
|
||||
// Note: it is much more efficient to draw lots of filled rectangles one after the other,
|
||||
// without empty rectangles between them, than to draw a mix.
|
||||
pub fn (ctx &Context) draw_rect_filled_no_context(x f32, y f32, w f32, h f32, c Color) {
|
||||
// Note: the following line is deliberately commented, compare to draw_rect_empty/5;
|
||||
// sgl.begin_quads()
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
sgl.v2f(x * ctx.scale, y * ctx.scale)
|
||||
sgl.v2f((x + w) * ctx.scale, y * ctx.scale)
|
||||
sgl.v2f((x + w) * ctx.scale, (y + h) * ctx.scale)
|
||||
sgl.v2f(x * ctx.scale, (y + h) * ctx.scale)
|
||||
// Note: the following line is deliberately commented, compare to draw_rect_filled/5;
|
||||
// sgl.end()
|
||||
}
|
||||
|
||||
pub enum PaintStyle {
|
||||
fill
|
||||
stroke
|
||||
|
|
|
@ -2306,6 +2306,23 @@ pub fn (expr Expr) pos() token.Pos {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn (expr Expr) is_constant() bool {
|
||||
return match expr {
|
||||
IntegerLiteral, FloatLiteral, BoolLiteral, StringLiteral {
|
||||
true
|
||||
}
|
||||
InfixExpr, CastExpr, ArrayInit {
|
||||
true
|
||||
}
|
||||
UnsafeExpr {
|
||||
expr.expr.is_constant()
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (expr Expr) is_lvalue() bool {
|
||||
return match expr {
|
||||
Ident, CTempVar { true }
|
||||
|
|
|
@ -661,8 +661,13 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
|
|||
}
|
||||
}
|
||||
if mut left is ast.Ident && left.info is ast.IdentVar {
|
||||
if left.info.is_static && right_sym.kind == .map {
|
||||
c.error('maps cannot be static', left.pos)
|
||||
if left.info.is_static {
|
||||
if right_sym.kind == .map {
|
||||
c.error('maps cannot be static', left.pos)
|
||||
} else if !right.is_constant() {
|
||||
c.error('cannot initialized static variable with non-constant value',
|
||||
left.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Single side check
|
||||
|
|
41
vlib/v/checker/tests/static_init_err.out
Normal file
41
vlib/v/checker/tests/static_init_err.out
Normal file
|
@ -0,0 +1,41 @@
|
|||
vlib/v/checker/tests/static_init_err.vv:10:2: warning: function `foo` must be called from an `unsafe` block
|
||||
8 |
|
||||
9 | fn main() {
|
||||
10 | foo()
|
||||
| ~~~~~
|
||||
11 | }
|
||||
vlib/v/checker/tests/static_init_err.vv:4:9: warning: unused variable: `aa`
|
||||
2 | fn foo() {
|
||||
3 | b := 23
|
||||
4 | static aa := b
|
||||
| ~~
|
||||
5 | static bb := 1 + 1
|
||||
6 | static cc := ''.str()
|
||||
vlib/v/checker/tests/static_init_err.vv:5:9: warning: unused variable: `bb`
|
||||
3 | b := 23
|
||||
4 | static aa := b
|
||||
5 | static bb := 1 + 1
|
||||
| ~~
|
||||
6 | static cc := ''.str()
|
||||
7 | }
|
||||
vlib/v/checker/tests/static_init_err.vv:6:9: warning: unused variable: `cc`
|
||||
4 | static aa := b
|
||||
5 | static bb := 1 + 1
|
||||
6 | static cc := ''.str()
|
||||
| ~~
|
||||
7 | }
|
||||
8 |
|
||||
vlib/v/checker/tests/static_init_err.vv:4:9: error: cannot initialized static variable with non-constant value
|
||||
2 | fn foo() {
|
||||
3 | b := 23
|
||||
4 | static aa := b
|
||||
| ~~
|
||||
5 | static bb := 1 + 1
|
||||
6 | static cc := ''.str()
|
||||
vlib/v/checker/tests/static_init_err.vv:6:9: error: cannot initialized static variable with non-constant value
|
||||
4 | static aa := b
|
||||
5 | static bb := 1 + 1
|
||||
6 | static cc := ''.str()
|
||||
| ~~
|
||||
7 | }
|
||||
8 |
|
11
vlib/v/checker/tests/static_init_err.vv
Normal file
11
vlib/v/checker/tests/static_init_err.vv
Normal file
|
@ -0,0 +1,11 @@
|
|||
@[unsafe]
|
||||
fn foo() {
|
||||
b := 23
|
||||
static aa := b
|
||||
static bb := 1 + 1
|
||||
static cc := ''.str()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo()
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue