修改前
修改后
6.0 Recovery 模式横屏修改方法
修改相关文件
bootable
ecoveryminuiAndroid.mk
bootable
ecoveryminuimt_graphic_rotate.cpp
bootable
ecoveryminuimt_graphic_rotate.h
bootable
ecoveryminuigraphics_fbdev.cpp
bootable
ecoveryminuiminui.h
1、在 Android.mk 中增加 mt_graphic_rotate.cpp 编译项
LOCAL_SRC_FILES :=
events.cpp
graphics.cpp
graphics_adf.cpp
graphics_drm.cpp
graphics_fbdev.cpp
resources.cpp
#cczheng add
LOCAL_SRC_FILES += mt_graphic_rotate.cpp
2、对比修改 mt_graphic_rotate.cpp,没有则直接复制以下类
/*
* Copyright (C) 2014 MediaTek Inc.
* Modification based on code covered by the mentioned copyright
* and/or permission notice(s).
*/
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <linux/fb.h>
#include <linux/kd.h>
#include "minui.h"
#include "graphics.h"
GRSurface __gr_canvas;
GRSurface* gr_canvas = NULL;
int rotate_index=-1;
static void print_surface_info(GRSurface *s, const char *name)
{
printf("[graphics] %s > Height:%d, Width:%d, PixelBytes:%d, RowBytes:%d, Size:%d, Data: 0x%08" PRIxPTR "
",
name, s->height, s->width, s->pixel_bytes, s->row_bytes, s->height* s->row_bytes, (uintptr_t) s->data);
}
// Read configuration from MTK_LCM_PHYSICAL_ROTATION
#ifndef MTK_LCM_PHYSICAL_ROTATION
#define MTK_LCM_PHYSICAL_ROTATION "undefined"
#endif
static int rotate_config(GRSurface *gr_draw)
{
if (rotate_index<0)
{
if (gr_draw->pixel_bytes != 4) rotate_index=0; // support 4 bytes pixel only
else if (0 == strncmp(MTK_LCM_PHYSICAL_ROTATION, "90", 2)) rotate_index=1;
else if (0 == strncmp(MTK_LCM_PHYSICAL_ROTATION, "180", 3)) rotate_index=2;
else if (0 == strncmp(MTK_LCM_PHYSICAL_ROTATION, "270", 3)) rotate_index=3;
else rotate_index=0;
printf("[graphics] rotate_config %d %s
", rotate_index, MTK_LCM_PHYSICAL_ROTATION);
}
return rotate_index;
}
#define swap(x, y, type) {type z; z=x; x=y; y=z;}
// Allocate and setup the canvas object
void rotate_canvas_init(GRSurface *gr_draw)
{
gr_canvas = &__gr_canvas;
memcpy(gr_canvas, gr_draw, sizeof(GRSurface));
// Swap canvas' height and width, if the rotate angle is 90" or 270"
if (rotate_config(gr_draw)%2) {
swap(gr_canvas->width, gr_canvas->height, int);
gr_canvas->row_bytes = gr_canvas->width * gr_canvas->pixel_bytes;
}
gr_canvas->data = (unsigned char*) malloc(gr_canvas->height * gr_canvas->row_bytes);
if (gr_canvas->data == NULL) {
printf("[graphics] rotate_canvas_init() malloc gr_canvas->data failed
");
gr_canvas = NULL;
return;
}
memset(gr_canvas->data, 0, gr_canvas->height * gr_canvas->row_bytes);
print_surface_info(gr_draw, "gr_draw");
print_surface_info(gr_canvas, "gr_canvas");
}
// Cleanup the canvas
void rotate_canvas_exit(void)
{
if (gr_canvas) {
if (gr_canvas->data)
free(gr_canvas->data);
free(gr_canvas);
}
gr_canvas=NULL;
}
// Return the canvas object
GRSurface *rotate_canvas_get(GRSurface *gr_draw)
{
// Initialize the canvas, if it was not exist.
if (gr_canvas==NULL)
rotate_canvas_init(gr_draw);
return gr_canvas;
}
// Surface Rotate Routines
static void rotate_surface_0(GRSurface *dst, GRSurface *src)
{
memcpy(dst->data, src->data, src->height*src->row_bytes);
}
static void rotate_surface_270(GRSurface *dst, GRSurface *src)
{
int v, w, h;
unsigned int *src_pixel;
unsigned int *dst_pixel;
for (h=0, v=src->width-1; h<dst->height; h++, v--) {
for (w=0; w<dst->width; w++) {
dst_pixel = (unsigned int *)(dst->data + dst->row_bytes*h);
src_pixel = (unsigned int *)(src->data + src->row_bytes*w);
*(dst_pixel+w)=*(src_pixel+v);
}
}
}
static void rotate_surface_180(GRSurface *dst, GRSurface *src)
{
int v, w, k, h;
unsigned int *src_pixel;
unsigned int *dst_pixel;
for (h=0, k=src->height-1; h<dst->height && k>=0 ; h++, k--) {
dst_pixel = (unsigned int *)(dst->data + dst->row_bytes*h);
src_pixel = (unsigned int *)(src->data + src->row_bytes*k);
for (w=0, v=src->width-1; w<dst->width && v>=0; w++, v--) {
*(dst_pixel+w)=*(src_pixel+v);
}
}
}
static void rotate_surface_90(GRSurface *dst, GRSurface *src)
{
int w, k, h;
unsigned int *src_pixel;
unsigned int *dst_pixel;
for (h=0; h<dst->height; h++) {
for (w=0, k=src->height-1; w<dst->width; w++, k--) {
dst_pixel = (unsigned int *)(dst->data + dst->row_bytes*h);
src_pixel = (unsigned int *)(src->data + src->row_bytes*k);
*(dst_pixel+w)=*(src_pixel+h);
}
}
}
typedef void (*rotate_surface_t) (GRSurface *, GRSurface *);
rotate_surface_t rotate_func[4]=
{
rotate_surface_0,
rotate_surface_90,
rotate_surface_180,
rotate_surface_270
};
// rotate and copy src* surface to dst surface
void rotate_surface(GRSurface *dst, GRSurface *src)
{
rotate_surface_t rotate;
rotate=rotate_func[rotate_config(dst)];
rotate(dst, src);
}
3、对比修改 mt_graphic_rotate.h,没有则直接复制以下类
/*
* Copyright (C) 2014 MediaTek Inc.
* Modification based on code covered by the mentioned copyright
* and/or permission notice(s).
*/
#ifndef MT_GRAPHICS_ROTATE_H_
#define MT_GRAPHICS_ROTATE_H_
#include "minui.h"
void rotate_canvas_exit(void);
void rotate_canvas_init(GRSurface *gr_draw);
void rotate_surface(GRSurface *dst, GRSurface *src);
GRSurface *rotate_canvas_get(GRSurface *gr_draw);
#endif
4、对比修改 graphics_fbdev.cpp,没有则直接复制以下类
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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
*
* http://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.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <linux/fb.h>
#include <linux/kd.h>
#include "minui.h"
#include "graphics.h"
#include "mt_graphic_rotate.h"
static GRSurface* fbdev_init(minui_backend*);
static GRSurface* fbdev_flip(minui_backend*);
static void fbdev_blank(minui_backend*, bool);
static void fbdev_exit(minui_backend*);
static GRSurface gr_framebuffer[2];
static bool double_buffered;
static GRSurface* gr_draw = NULL;
static int displayed_buffer;
static fb_var_screeninfo vi;
static int fb_fd = -1;
static minui_backend my_backend = {
.init = fbdev_init,
.flip = fbdev_flip,
.blank = fbdev_blank,
.exit = fbdev_exit,
};
minui_backend* open_fbdev() {
return &my_backend;
}
static void fbdev_blank(minui_backend* backend __unused, bool blank)
{
int ret;
ret = ioctl(fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK);
if (ret < 0)
perror("ioctl(): blank");
}
static void set_displayed_framebuffer(unsigned n)
{
if (n > 1 || !double_buffered) return;
vi.yres_virtual = gr_framebuffer[0].height * 2;
vi.yoffset = n * gr_framebuffer[0].height;
vi.bits_per_pixel = gr_framebuffer[0].pixel_bytes * 8;
if (ioctl(fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
perror("active fb swap failed");
}
displayed_buffer = n;
}
static GRSurface* fbdev_init(minui_backend* backend) {
int fd = open("/dev/graphics/fb0", O_RDWR);
if (fd == -1) {
perror("cannot open fb0");
return NULL;
}
fb_fix_screeninfo fi;
if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
perror("failed to get fb0 info");
close(fd);
return NULL;
}
if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
perror("failed to get fb0 info");
close(fd);
return NULL;
}
// We print this out for informational purposes only, but
// throughout we assume that the framebuffer device uses an RGBX
// pixel format. This is the case for every development device I
// have access to. For some of those devices (eg, hammerhead aka
// Nexus 5), FBIOGET_VSCREENINFO *reports* that it wants a
// different format (XBGR) but actually produces the correct
// results on the display when you write RGBX.
//
// If you have a device that actually *needs* another pixel format
// (ie, BGRX, or 565), patches welcome...
printf("fb0 reports (possibly inaccurate):
"
" vi.bits_per_pixel = %d
"
" vi.red.offset = %3d .length = %3d
"
" vi.green.offset = %3d .length = %3d
"
" vi.blue.offset = %3d .length = %3d
",
vi.bits_per_pixel,
vi.red.offset, vi.red.length,
vi.green.offset, vi.green.length,
vi.blue.offset, vi.blue.length);
void* bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (bits == MAP_FAILED) {
perror("failed to mmap framebuffer");
close(fd);
return NULL;
}
memset(bits, 0, fi.smem_len);
gr_framebuffer[0].width = vi.xres;
gr_framebuffer[0].height = vi.yres;
gr_framebuffer[0].row_bytes = fi.line_length;
gr_framebuffer[0].pixel_bytes = vi.bits_per_pixel / 8;
gr_framebuffer[0].data = reinterpret_cast<uint8_t*>(bits);
memset(gr_framebuffer[0].data, 0, gr_framebuffer[0].height * gr_framebuffer[0].row_bytes);
/* check if we can use double buffering */
printf("[graphics] vi.yres * fi.line_length = %d * %d * 2 = %d, fi.smem_len=%d
",
vi.yres, fi.line_length, vi.yres * fi.line_length * 2, fi.smem_len);
if (vi.yres * fi.line_length * 2 <= fi.smem_len) {
double_buffered = true;
printf("[graphics] double buffered
");
memcpy(gr_framebuffer+1, gr_framebuffer, sizeof(GRSurface));
gr_framebuffer[1].data = gr_framebuffer[0].data +
gr_framebuffer[0].height * gr_framebuffer[0].row_bytes;
gr_draw = gr_framebuffer+1;
} else {
double_buffered = false;
printf("[graphics] without double buffer
");
// Without double-buffering, we allocate RAM for a buffer to
// draw in, and then "flipping" the buffer consists of a
// memcpy from the buffer we allocated to the framebuffer.
gr_draw = (GRSurface*) malloc(sizeof(GRSurface));
memcpy(gr_draw, gr_framebuffer, sizeof(GRSurface));
gr_draw->data = (unsigned char*) malloc(gr_draw->height * gr_draw->row_bytes);
if (!gr_draw->data) {
perror("failed to allocate in-memory surface");
return NULL;
}
}
memset(gr_draw->data, 0, gr_draw->height * gr_draw->row_bytes);
fb_fd = fd;
set_displayed_framebuffer(0);
printf("framebuffer: %d (%d x %d)
", fb_fd, gr_draw->width, gr_draw->height);
#if 0 // to avoid display blink due to display driver not disable backlight after kernel standardization, so that temp state between display suspend/resume is shown
fbdev_blank(backend, true);
fbdev_blank(backend, false);
#endif
return rotate_canvas_get(gr_draw);
}
static GRSurface* fbdev_flip(minui_backend* backend __unused) {
rotate_surface(gr_draw, rotate_canvas_get(gr_draw));
if (double_buffered) {
#if defined(RECOVERY_BGRA)
// In case of BGRA, do some byte swapping
unsigned int idx;
unsigned char tmp;
unsigned char* ucfb_vaddr = (unsigned char*)gr_draw->data;
for (idx = 0 ; idx < (gr_draw->height * gr_draw->row_bytes);
idx += 4) {
tmp = ucfb_vaddr[idx];
ucfb_vaddr[idx ] = ucfb_vaddr[idx + 2];
ucfb_vaddr[idx + 2] = tmp;
}
#endif
// Change gr_draw to point to the buffer currently displayed,
// then flip the driver so we're displaying the other buffer
// instead.
gr_draw = gr_framebuffer + displayed_buffer;
set_displayed_framebuffer(1-displayed_buffer);
} else {
// Copy from the in-memory surface to the framebuffer.
memcpy(gr_framebuffer[0].data, gr_draw->data,
gr_draw->height * gr_draw->row_bytes);
}
return rotate_canvas_get(gr_draw);
}
static void fbdev_exit(minui_backend* backend __unused) {
close(fb_fd);
fb_fd = -1;
rotate_canvas_exit();
if (!double_buffered && gr_draw) {
free(gr_draw->data);
free(gr_draw);
}
gr_draw = NULL;
}
5、对比修改 minui.h,没有则直接复制以下类
/*
* Copyright (C) 2007 The Android Open Source Project
*
* 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
*
* http://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.
*/
#ifndef _MINUI_H_
#define _MINUI_H_
#include <sys/types.h>
#include <functional>
//
// Graphics.
//
struct GRSurface {
int width;
int height;
int row_bytes;
int pixel_bytes;
unsigned char* data;
};
int gr_init();
void gr_exit();
int gr_fb_width();
int gr_fb_height();
void gr_flip();
void gr_fb_blank(bool blank);
void gr_clear(); // clear entire surface to current color
void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
void gr_fill(int x1, int y1, int x2, int y2);
void gr_text(int x, int y, const char *s, bool bold);
void gr_texticon(int x, int y, GRSurface* icon);
int gr_measure(const char *s);
void gr_font_size(int *x, int *y);
void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy);
unsigned int gr_get_width(GRSurface* surface);
unsigned int gr_get_height(GRSurface* surface);
//
// Input events.
//
struct input_event;
// TODO: move these over to std::function.
typedef int (*ev_callback)(int fd, uint32_t epevents, void* data);
typedef int (*ev_set_key_callback)(int code, int value, void* data);
int ev_init(ev_callback input_cb, void* data);
void ev_exit();
int ev_add_fd(int fd, ev_callback cb, void* data);
void ev_iterate_available_keys(std::function<void(int)> f);
int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data);
// 'timeout' has the same semantics as poll(2).
// 0 : don't block
// < 0 : block forever
// > 0 : block for 'timeout' milliseconds
int ev_wait(int timeout);
int ev_get_input(int fd, uint32_t epevents, input_event* ev);
void ev_dispatch();
int ev_get_epollfd();
//
// Resources
//
// res_create_*_surface() functions return 0 if no error, else
// negative.
//
// A "display" surface is one that is intended to be drawn to the
// screen with gr_blit(). An "alpha" surface is a grayscale image
// interpreted as an alpha mask used to render text in the current
// color (with gr_text() or gr_texticon()).
//
// All these functions load PNG images from "/res/images/${name}.png".
// Load a single display surface from a PNG image.
int res_create_display_surface(const char* name, GRSurface** pSurface);
// Load an array of display surfaces from a single PNG image. The PNG
// should have a 'Frames' text chunk whose value is the number of
// frames this image represents. The pixel data itself is interlaced
// by row.
int res_create_multi_display_surface(const char* name,
int* frames, GRSurface*** pSurface);
// Load a single alpha surface from a grayscale PNG image.
int res_create_alpha_surface(const char* name, GRSurface** pSurface);
// Load part of a grayscale PNG image that is the first match for the
// given locale. The image is expected to be a composite of multiple
// translations of the same text, with special added rows that encode
// the subimages' size and intended locale in the pixel data. See
// development/tools/recovery_l10n for an app that will generate these
// specialized images from Android resources.
int res_create_localized_alpha_surface(const char* name, const char* locale,
GRSurface** pSurface);
// Free a surface allocated by any of the res_create_*_surface()
// functions.
void res_free_surface(GRSurface* surface);
#endif
8.1 Recovery 模式横屏修改方法
8.1 的修改步骤和 6.0 大体差不多,前三步都一样,请参考上面的,由于 8.1 中不需要 minui.h 文件,所以 mt_graphic_rotate.h 和 mt_graphic_rotate.cpp 中 需要注释
//#include "minui.h"
4、对比修改 graphics_fbdev.cpp
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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
*
* http://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.
*/
#include "graphics_fbdev.h"
#include <fcntl.h>
#include <linux/fb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include "minui/minui.h"
//cczheng add for rotateCanvas
#include "mt_graphic_rotate.h"
MinuiBackendFbdev::MinuiBackendFbdev() : gr_draw(nullptr), fb_fd(-1) {}
void MinuiBackendFbdev::Blank(bool blank) {
int ret = ioctl(fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK);
if (ret < 0) perror("ioctl(): blank");
}
void MinuiBackendFbdev::SetDisplayedFramebuffer(unsigned n) {
if (n > 1 || !double_buffered) return;
vi.yres_virtual = gr_framebuffer[0].height * 2;
vi.yoffset = n * gr_framebuffer[0].height;
vi.bits_per_pixel = gr_framebuffer[0].pixel_bytes * 8;
if (ioctl(fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
perror("active fb swap failed");
}
displayed_buffer = n;
}
GRSurface* MinuiBackendFbdev::Init() {
int fd = open("/dev/graphics/fb0", O_RDWR);
if (fd == -1) {
perror("cannot open fb0");
return nullptr;
}
fb_fix_screeninfo fi;
if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
perror("failed to get fb0 info");
close(fd);
return nullptr;
}
if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
perror("failed to get fb0 info");
close(fd);
return nullptr;
}
// We print this out for informational purposes only, but
// throughout we assume that the framebuffer device uses an RGBX
// pixel format. This is the case for every development device I
// have access to. For some of those devices (eg, hammerhead aka
// Nexus 5), FBIOGET_VSCREENINFO *reports* that it wants a
// different format (XBGR) but actually produces the correct
// results on the display when you write RGBX.
//
// If you have a device that actually *needs* another pixel format
// (ie, BGRX, or 565), patches welcome...
printf(
"fb0 reports (possibly inaccurate):
"
" vi.bits_per_pixel = %d
"
" vi.red.offset = %3d .length = %3d
"
" vi.green.offset = %3d .length = %3d
"
" vi.blue.offset = %3d .length = %3d
",
vi.bits_per_pixel, vi.red.offset, vi.red.length, vi.green.offset, vi.green.length,
vi.blue.offset, vi.blue.length);
void* bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (bits == MAP_FAILED) {
perror("failed to mmap framebuffer");
close(fd);
return nullptr;
}
memset(bits, 0, fi.smem_len);
gr_framebuffer[0].width = vi.xres;
gr_framebuffer[0].height = vi.yres;
gr_framebuffer[0].row_bytes = fi.line_length;
gr_framebuffer[0].pixel_bytes = vi.bits_per_pixel / 8;
gr_framebuffer[0].data = static_cast<uint8_t*>(bits);
memset(gr_framebuffer[0].data, 0, gr_framebuffer[0].height * gr_framebuffer[0].row_bytes);
/* check if we can use double buffering */
if (vi.yres * fi.line_length * 2 <= fi.smem_len) {
double_buffered = true;
memcpy(gr_framebuffer + 1, gr_framebuffer, sizeof(GRSurface));
gr_framebuffer[1].data =
gr_framebuffer[0].data + gr_framebuffer[0].height * gr_framebuffer[0].row_bytes;
gr_draw = gr_framebuffer + 1;
} else {
double_buffered = false;
// Without double-buffering, we allocate RAM for a buffer to
// draw in, and then "flipping" the buffer consists of a
// memcpy from the buffer we allocated to the framebuffer.
gr_draw = static_cast<GRSurface*>(malloc(sizeof(GRSurface)));
memcpy(gr_draw, gr_framebuffer, sizeof(GRSurface));
gr_draw->data = static_cast<unsigned char*>(malloc(gr_draw->height * gr_draw->row_bytes));
if (!gr_draw->data) {
perror("failed to allocate in-memory surface");
return nullptr;
}
}
memset(gr_draw->data, 0, gr_draw->height * gr_draw->row_bytes);
fb_fd = fd;
SetDisplayedFramebuffer(0);
printf("framebuffer: %d (%d x %d)
", fb_fd, gr_draw->width, gr_draw->height);
#if 0
Blank(true);
Blank(false);
#endif
//return gr_draw;
//cczheng add for rotateCanvas
return rotate_canvas_get(gr_draw);
}
GRSurface* MinuiBackendFbdev::Flip() {
//cczheng add for rotateCanvas
rotate_surface(gr_draw, rotate_canvas_get(gr_draw));
if (double_buffered) {
// Change gr_draw to point to the buffer currently displayed,
// then flip the driver so we're displaying the other buffer
// instead.
gr_draw = gr_framebuffer + displayed_buffer;
SetDisplayedFramebuffer(1 - displayed_buffer);
} else {
// Copy from the in-memory surface to the framebuffer.
memcpy(gr_framebuffer[0].data, gr_draw->data, gr_draw->height * gr_draw->row_bytes);
}
//return gr_draw;
//cczheng add for rotateCanvas
return rotate_canvas_get(gr_draw);
}
MinuiBackendFbdev::~MinuiBackendFbdev() {
close(fb_fd);
fb_fd = -1;
//cczheng add for rotateCanvas
rotate_canvas_exit();
if (!double_buffered && gr_draw) {
free(gr_draw->data);
free(gr_draw);
}
gr_draw = nullptr;
}
修改旋转角度,在 mt_graphic_rotate.cpp 中的 rotate_config(GRSurface gr_draw)
旋转90度就将 return rotate_index 直接改为 return 1,
依次类推转 180度, 改为 return 2, 270 度改为 return 3.
注意旋转方向为顺时针旋转
我修改的情况对应 return 3.