texture_rgba_renderer 0.0.16 copy "texture_rgba_renderer: ^0.0.16" to clipboard
texture_rgba_renderer: ^0.0.16 copied to clipboard

A texture helper which brings a high level api to handle BGRA data.

example/lib/main.dart

import 'dart:io';
import 'dart:ffi';
import 'dart:math';
import 'dart:typed_data';
import 'package:ffi/ffi.dart';

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

import 'package:flutter/services.dart';
import 'package:texture_rgba_renderer/texture_rgba_renderer.dart';

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

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _textureRgbaRendererPlugin = TextureRgbaRenderer();
  int textureId = -1;
  int height = 768;
  int width = 1377;
  int cnt = 0;
  var key = 0;
  int texturePtr = 0;
  final random = Random();
  Uint8List? data;
  Timer? _timer;
  int time = 0;
  int method = 0;
  final strideAlign = Platform.isMacOS ? 64 : 1;

  @override
  void initState() {
    super.initState();
    _textureRgbaRendererPlugin.createTexture(key).then((textureId) {
      if (textureId != -1) {
        debugPrint("Texture register success, textureId=$textureId");
        _textureRgbaRendererPlugin.getTexturePtr(key).then((value) {
          debugPrint("texture ptr: ${value.toRadixString(16)}");
          setState(() {
            texturePtr = value;
          });
        });
        setState(() {
          this.textureId = textureId;
        });
      } else {
        return;
      }
    });
  }

  void start(int methodId) {
    debugPrint("start mockPic");
    method = methodId;
    final rowBytes = (width * 4 + strideAlign - 1) & (~(strideAlign - 1));
    final picDataLength = rowBytes * height;
    debugPrint('REMOVE ME =============================== rowBytes $rowBytes');
    _timer?.cancel();
    // 60 fps
    _timer =
        Timer.periodic(const Duration(milliseconds: 1000 ~/ 60), (timer) async {
      if (methodId == 0) {
        // Method.1: with MethodChannel
        data = mockPicture(width, height, rowBytes, picDataLength);
        final t1 = DateTime.now().microsecondsSinceEpoch;
        final res = await _textureRgbaRendererPlugin.onRgba(
            key, data!, height, width, strideAlign);
        final t2 = DateTime.now().microsecondsSinceEpoch;
        setState(() {
          time = t2 - t1;
        });
        if (!res) {
          debugPrint("WARN: render failed");
        }
      } else {
        final dataPtr = mockPicturePtr(width, height, rowBytes, picDataLength);
        // Method.2: with native ffi
        final t1 = DateTime.now().microsecondsSinceEpoch;
        Native.instance.onRgba(Pointer.fromAddress(texturePtr).cast<Void>(),
            dataPtr, picDataLength, width, height, strideAlign);
        final t2 = DateTime.now().microsecondsSinceEpoch;
        setState(() {
          time = t2 - t1;
        });
        malloc.free(dataPtr);
      }
    });
  }

  @override
  void dispose() {
    _timer?.cancel();
    if (key != -1) {
      _textureRgbaRendererPlugin.closeTexture(key);
    }
    super.dispose();
  }

  Uint8List mockPicture(int width, int height, int rowBytes, int length) {
    final pic = List.generate(length, (index) {
      final r = index / rowBytes;
      final c = (index % rowBytes) / 4;
      final p = index & 0x03;
      if (c > 20 && c < 30) {
        if (r > 20 && r < 25) {
          if (p == 0 || p == 3) {
            return 255;
          } else {
            return 0;
          }
        }
        if (r > 40 && r < 45) {
          if (p == 1 || p == 3) {
            return 255;
          } else {
            return 0;
          }
        }
        if (r > 60 && r < 65) {
          if (p == 2 || p == 3) {
            return 255;
          } else {
            return 0;
          }
        }
      }
      return 255;
    });
    return Uint8List.fromList(pic);
  }

  Pointer<Uint8> mockPicturePtr(
      int width, int height, int rowBytes, int length) {
    final pic = List.generate(length, (index) {
      final r = index / rowBytes;
      final c = (index % rowBytes) / 4;
      final p = index & 0x03;
      final edgeH = (c >= 0 && c < 10) || ((c >= width - 10) && c < width);
      final edgeW = (r >= 0 && r < 10) || ((r >= height - 10) && r < height);
      if (edgeH || edgeW) {
        if (p == 0 || p == 3) {
          return 255;
        } else {
          return 0;
        }
      }
      return 255;
    });
    final picAddr = malloc.allocate(pic.length).cast<Uint8>();
    final list = picAddr.asTypedList(pic.length);
    list.setRange(0, pic.length, pic);
    return picAddr;
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Expanded(
              child: textureId == -1
                  ? const Offstage()
                  : Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Container(
                          alignment: Alignment.center,
                          decoration: const BoxDecoration(color: Colors.blue),
                          // decoration: const BoxDecoration(color: Colors.black),
                          // width: width.toDouble(),
                          // height: height.toDouble(),
                          child: Texture(textureId: textureId)),
                    ),
            ),
            Text(
                "texture id: $textureId, texture memory address: ${texturePtr.toRadixString(16)}"),
            TextButton.icon(
              label: const Text("play with texture (method channel API)"),
              icon: const Icon(Icons.play_arrow),
              onPressed: () => start(0),
            ),
            TextButton.icon(
              label: const Text("play with texture (native API, faster)"),
              icon: const Icon(Icons.play_arrow),
              onPressed: () => start(1),
            ),
            Text(
                "Current mode: ${method == 0 ? 'Method Channel API' : 'Native API'}"),
            time != 0 ? Text("FPS: ${1000000 ~/ time} fps") : const Offstage()
          ],
        ),
      ),
    );
  }
}
6
likes
140
pub points
95%
popularity

Publisher

verified publisherkingtous.cn

A texture helper which brings a high level api to handle BGRA data.

Repository (GitHub)
View/report issues

Documentation

API reference

License

Apache-2.0 (LICENSE)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on texture_rgba_renderer