Flutter插件sw_rend的介绍与使用方法详解

Flutter插件sw_rend的介绍与使用方法详解

SwRend 是一个用于直接像素渲染纹理的插件。此插件目前支持 Windows、Android 和 Linux 平台。

SoftwareTexture

SoftwareTexture 表示可以由软件显示的像素数据纹理。在创建 SoftwareTexture 时,需要通过传递其大小(以像素为单位)作为 Size 参数给构造函数。

在使用 SoftwareTexture 之前,必须调用 generateTexture 方法,该方法会调用特定平台的功能来在设备上创建纹理并检索纹理 ID。每个 SoftwareTexture 都包含一个名为 bufferUint8List,它以行优先顺序存储 RGBA 格式的像素数据。调用 draw 方法会将 buffer 中的内容推送到底层设备纹理的像素数据,并且如果可选参数 redraw 没有指定为 false,则会重新绘制纹理。可以通过 SoftwareTexturetextureIDTexture 小部件中显示 SoftwareTexture 的内容。

示例代码

/*
Copyright 2022 Google LLC

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

    https://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.
 */

import 'dart:math';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:sw_rend/software_texture.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int width = 300, height = 300;
  num scale = 1;
  DateTime start = DateTime.now();
  DateTime last = DateTime.now();
  int frames = 0;
  double fps = 1;
  SoftwareTexture? texture, texture2;
  late Uint8List gol;

  [@override](/user/override)
  void initState() {
    super.initState();
    initPlatformState();
  }

  // 平台消息是异步的,因此我们在异步方法中初始化。
  Future<void> initPlatformState() async {
    gol = Uint8List(width * height);
    Random r = Random();
    for (int i = 0; i < width * height; i++) {
      gol[i] = r.nextBool() ? 255 : 0;
    }

    SoftwareTexture tex =
        SoftwareTexture(Size(width.toDouble(), height.toDouble()));
    await tex.generateTexture().then((void v) {
      if (kDebugMode) {
        print("TEXTURE = ${tex.textureId}");
      }
      texture = tex;
    });
    tex = SoftwareTexture(Size(width.toDouble(), height.toDouble()));
    await tex.generateTexture().then((void v) {
      texture2 = tex;
    });

    // 如果小部件在异步平台消息处理过程中从树中移除,则我们希望丢弃回复而不是调用
    // setState 来更新我们的非存在的外观。
    if (!mounted) return;

    tick();
  }

  Future<void> tick() async {
    num targetFps = 200;
    Duration wait = Duration(microseconds: 1e6 ~/ targetFps);
    DateTime pre = DateTime.now();
    await noisy();
    DateTime now = DateTime.now();
    frames++;
    fps = 1e6 * frames / now.difference(start).inMicroseconds;
    if (frames >= 50) {
      setState(() {});
      frames = 0;
      start = now;
    }
    last = now;
    wait = wait - now.difference(pre);
    Timer(wait, tick);
  }

  Future<void> game() async {
    Uint8List newGol = Uint8List(width * height);
    for (int y = 0; y < height; y++) {
      for (int x = 0; x < width; x++) {
        int index = y * width + x;
        int neighbors = 0;

        for (int dy = y-1; dy <= y+1; dy++) {
          for (int dx = x - 1; dx <= x + 1; dx++) {
            if (dy == y && dx == x) {
              continue;
            }
            if (gol[dx % width + (dy % height) * width] != 0) {
              neighbors += 1;
            }
          }
        }

        if (neighbors < 2) {
          newGol[index] = 0;
        } else if (neighbors > 3 && gol[index] != 0) {
          newGol[index] = 0;
        } else if (neighbors == 3) {
          newGol[index] = 255;
        } else {
          newGol[index] = gol[index];
        }
      }
    }
    gol.setAll(0, newGol);
  }

  Future<void> noisy() async {
    await game();
    Uint8List pixels = texture!.buffer;
    await texture!.readPixels();
    Random r = Random();
    for (int i = 0; i < width * height * 4; i += 4) {
      int index = i ~/ 4;
      int color = gol[index];
      pixels[i] = color;
      pixels[i + 1] = color;
      pixels[i + 2] = color;
      pixels[i + 3] = 255;
    }
    await texture!.draw();
    pixels = texture2!.buffer;
    for (int i = 0; i < width * height * 4; i += 4) {
      int x = (i ~/ 4) % width;
      pixels[i] = r.nextInt(256) ~/ (2 + r.nextInt(4));
      pixels[i + 1] = r.nextInt(256) ~/ (2 + r.nextInt(4));
      pixels[i + 2] = x & 255;
      pixels[i + 3] = 255;
    }
    await texture2!.draw();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
      appBar: AppBar(
        title: Text('$fps'),
      ),
      body: Center(
        child: SizedBox(
          width: width.toDouble() * scale,
          child: ListView(
            children: [
              const Text('Text goes here'),
              Container(
                  width: width.toDouble() * scale,
                  height: height.toDouble() * scale,
                  color: Colors.green,
                  child: (texture == null)
                      ? null
                      : ConstrainedBox(
                      constraints: BoxConstraints(
                          minWidth: width.toDouble() * scale,
                          minHeight: height.toDouble() * scale),
                      child: Texture(
                        textureId: texture!.textureId,
                        filterQuality: FilterQuality.none,
                      ))),
              Container(
                  width: width.toDouble() * scale,
                  height: height.toDouble() * scale,
                  color: Colors.red,
                  child: (texture2 == null)
                      ? null
                      : ConstrainedBox(
                      constraints: BoxConstraints(
                          minWidth: width.toDouble() * scale,
                          minHeight: height.toDouble() * scale),
                      child: Texture(
                        textureId: texture2!.textureId,
                        filterQuality: FilterQuality.none,
                      ))),
            ],
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: const Text('Button'),
        onPressed: () {
          noisy();
        },
      ),
    ));
  }
}

更多关于Flutter插件sw_rend的介绍与使用方法详解的实战教程也可以访问 https://www.itying.com/category-92-b0.html

回到顶部