free will privileges
loosely copy pasted and C++-ified from project fywi
This commit is contained in:
parent
d69c8e3a5e
commit
ba340d9127
@ -9,7 +9,7 @@ CXXFLAGS ?= -std=c++20 -Wall -Wpedantic -Wextra -g -Og
|
|||||||
LDFLAGS ?=
|
LDFLAGS ?=
|
||||||
|
|
||||||
NAME := suwi
|
NAME := suwi
|
||||||
libs := m z portaudio SDL3
|
libs := m z SDL3
|
||||||
includes := src/
|
includes := src/
|
||||||
cflags := $(addprefix -I,${includes}) ${CFLAGS}
|
cflags := $(addprefix -I,${includes}) ${CFLAGS}
|
||||||
cxxflags := $(addprefix -I,${includes}) ${CXXFLAGS}
|
cxxflags := $(addprefix -I,${includes}) ${CXXFLAGS}
|
||||||
|
|||||||
@ -9,19 +9,19 @@ pictures := $(patsubst src/%.ase,out/%.picture, $(wildcard src/*.ase))
|
|||||||
out/suwi.assets: ${shaders} ${pictures} | out/assetsmk
|
out/suwi.assets: ${shaders} ${pictures} | out/assetsmk
|
||||||
printf '%s\0' $^ | sed -nz 'p;s:.*/::p' | $| -c0f out/suwi.assets -F - -N -
|
printf '%s\0' $^ | sed -nz 'p;s:.*/::p' | $| -c0f out/suwi.assets -F - -N -
|
||||||
|
|
||||||
out/%.shader: src/%.glsl utl/vert.awk utl/frag.awk
|
out/%.shader: src/%.glsl utl/vert.awk utl/frag.awk | out/
|
||||||
awk -f utl/vert.awk $< > $@
|
awk -f utl/vert.awk $< > $@
|
||||||
printf '\0' >> $@
|
printf '\0' >> $@
|
||||||
awk -f utl/frag.awk $< >> $@
|
awk -f utl/frag.awk $< >> $@
|
||||||
printf '\0' >> $@
|
printf '\0' >> $@
|
||||||
|
|
||||||
out/%.shader: src/%.frag utl/vert.awk utl/frag.awk src/default.glsl
|
out/%.shader: src/%.frag utl/vert.awk utl/frag.awk src/default.glsl | out/
|
||||||
awk -f utl/vert.awk src/default.glsl > $@
|
awk -f utl/vert.awk src/default.glsl > $@
|
||||||
printf '\0' >> $@
|
printf '\0' >> $@
|
||||||
cat $< >> $@
|
cat $< >> $@
|
||||||
printf '\0' >> $@
|
printf '\0' >> $@
|
||||||
|
|
||||||
out/%.png: src/%.ase
|
out/%.png: src/%.ase | out/
|
||||||
${PRITE} -b $< --save-as $@
|
${PRITE} -b $< --save-as $@
|
||||||
|
|
||||||
out/%.picture: out/picmake out/%.png
|
out/%.picture: out/picmake out/%.png
|
||||||
|
|||||||
166
src/input.c++
Normal file
166
src/input.c++
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
#include "input.h++"
|
||||||
|
|
||||||
|
std::bitset<input::_LENGTH> input::_held, input::_pressed, input::_buffered, input::_buffer_mask;
|
||||||
|
|
||||||
|
struct input::keyboard input::keyboard;
|
||||||
|
SDL_Scancode input::keyboard::keybinds[input::_LENGTH][2] = {
|
||||||
|
{SDL_SCANCODE_UP, SDL_SCANCODE_W},
|
||||||
|
{SDL_SCANCODE_DOWN, SDL_SCANCODE_S},
|
||||||
|
{SDL_SCANCODE_LEFT, SDL_SCANCODE_A},
|
||||||
|
{SDL_SCANCODE_RIGHT, SDL_SCANCODE_D},
|
||||||
|
};
|
||||||
|
std::bitset<input::_LENGTH> input::keyboard::state[2];
|
||||||
|
|
||||||
|
SDL_JoystickID input::gamepad::joystick;
|
||||||
|
SDL_Gamepad *input::gamepad::controller;
|
||||||
|
SDL_GamepadButton input::gamepad::keybinds[input::_LENGTH][2] = {
|
||||||
|
{SDL_GAMEPAD_BUTTON_DPAD_UP, SDL_GAMEPAD_BUTTON_NORTH},
|
||||||
|
{SDL_GAMEPAD_BUTTON_DPAD_DOWN, SDL_GAMEPAD_BUTTON_SOUTH},
|
||||||
|
{SDL_GAMEPAD_BUTTON_DPAD_LEFT, SDL_GAMEPAD_BUTTON_WEST},
|
||||||
|
{SDL_GAMEPAD_BUTTON_DPAD_RIGHT, SDL_GAMEPAD_BUTTON_EAST},
|
||||||
|
};
|
||||||
|
std::bitset<input::_LENGTH> input::gamepad::state[2];
|
||||||
|
|
||||||
|
std::vector<struct input::touch::position> input::touch::positions;
|
||||||
|
std::bitset<input::_LENGTH> input::touch::state;
|
||||||
|
|
||||||
|
void input::tickle(void) {
|
||||||
|
_buffered &= _buffer_mask;
|
||||||
|
_buffer_mask.set();
|
||||||
|
_pressed = _held;
|
||||||
|
_held = keyboard.state[0] | keyboard.state[1] | gamepad.state[0] | gamepad.state[1] | touch.state ;
|
||||||
|
_pressed = ~_pressed & _held;
|
||||||
|
_buffered |= _pressed;
|
||||||
|
_buffered &= _held;
|
||||||
|
}
|
||||||
|
|
||||||
|
void input::touch::refresh(void) {
|
||||||
|
state.reset();
|
||||||
|
for (size_t i = 0; i < positions.size(); i++) {
|
||||||
|
if (positions[i].active) {
|
||||||
|
switch ((int) (positions[i].x * 5)) {
|
||||||
|
case 0:
|
||||||
|
state[input::LEFT] = true;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
state[input::RIGHT] = true;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
state[input::DOWN] = true;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
state[input::UP] = true;
|
||||||
|
break;
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void input::event(SDL_Event const &evt) {
|
||||||
|
switch (evt.type) {
|
||||||
|
case SDL_EVENT_KEY_DOWN:
|
||||||
|
case SDL_EVENT_KEY_UP:
|
||||||
|
if (evt.key.repeat) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned key = 0; key < input::_LENGTH; key++) {
|
||||||
|
if (evt.key.scancode == keyboard.keybinds[key][0]) {
|
||||||
|
keyboard.state[0][key] = evt.key.down;
|
||||||
|
}
|
||||||
|
if (evt.key.scancode == keyboard.keybinds[key][1]) {
|
||||||
|
keyboard.state[1][key] = evt.key.down;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_EVENT_MOUSE_MOTION:
|
||||||
|
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||||
|
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||||
|
case SDL_EVENT_MOUSE_WHEEL:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_EVENT_FINGER_UP: {
|
||||||
|
size_t const i = evt.tfinger.fingerID;
|
||||||
|
touch.positions[i].active = false;
|
||||||
|
touch::refresh();
|
||||||
|
} break;
|
||||||
|
case SDL_EVENT_FINGER_DOWN: {
|
||||||
|
size_t const i = evt.tfinger.fingerID;
|
||||||
|
if (i >= touch.positions.size()) {
|
||||||
|
#if 0
|
||||||
|
size_t const start = touch.allocated;
|
||||||
|
touch.allocated = i + 1;
|
||||||
|
touch.positions = realloc(touch.positions, sizeof (struct touch_vec) * touch.allocated);
|
||||||
|
if (i) { // hack for 0 - 1 = absurd-high number; all of RAM gets wiped
|
||||||
|
for (size_t index = start; index < i - 1; index++) {
|
||||||
|
touch.positions[index].active = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
touch.positions.resize(i + 1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
touch.positions[i].x = evt.tfinger.x;
|
||||||
|
touch.positions[i].y = evt.tfinger.y;
|
||||||
|
touch.positions[i].active = true;
|
||||||
|
touch::refresh();
|
||||||
|
} break;
|
||||||
|
case SDL_EVENT_FINGER_MOTION: {
|
||||||
|
size_t const i = evt.tfinger.fingerID;
|
||||||
|
touch.positions[i].x = evt.tfinger.x;
|
||||||
|
touch.positions[i].y = evt.tfinger.y;
|
||||||
|
touch::refresh();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case SDL_EVENT_GAMEPAD_ADDED:
|
||||||
|
if (gamepad.joystick != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((gamepad.controller = SDL_OpenGamepad(evt.gdevice.which)) != NULL) {
|
||||||
|
gamepad.joystick = evt.gdevice.which;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_EVENT_GAMEPAD_REMOVED:
|
||||||
|
if (gamepad.joystick == evt.gdevice.which) {
|
||||||
|
SDL_CloseGamepad(gamepad.controller);
|
||||||
|
gamepad.controller = NULL;
|
||||||
|
gamepad.joystick = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
||||||
|
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
||||||
|
if (gamepad.joystick == evt.gbutton.which) {
|
||||||
|
for (unsigned key = 0; key < input::_LENGTH; key++) {
|
||||||
|
if (evt.gbutton.button == gamepad.keybinds[key][0]) {
|
||||||
|
gamepad.state[0][key] = evt.gbutton.down;
|
||||||
|
}
|
||||||
|
if (evt.gbutton.button == gamepad.keybinds[key][1]) {
|
||||||
|
gamepad.state[1][key] = evt.gbutton.down;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_EVENT_JOYSTICK_AXIS_MOTION:
|
||||||
|
case SDL_EVENT_JOYSTICK_BALL_MOTION:
|
||||||
|
case SDL_EVENT_JOYSTICK_HAT_MOTION:
|
||||||
|
case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
|
||||||
|
case SDL_EVENT_JOYSTICK_BUTTON_UP:
|
||||||
|
case SDL_EVENT_JOYSTICK_ADDED:
|
||||||
|
break; // we dont care about these
|
||||||
|
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
||||||
|
case SDL_EVENT_GAMEPAD_REMAPPED:
|
||||||
|
case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN:
|
||||||
|
case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION:
|
||||||
|
case SDL_EVENT_GAMEPAD_TOUCHPAD_UP:
|
||||||
|
case SDL_EVENT_GAMEPAD_SENSOR_UPDATE:
|
||||||
|
case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED:
|
||||||
|
break; // we currently dont do anything about these
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/input.h++
Normal file
58
src/input.h++
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <SDL3/SDL_events.h>
|
||||||
|
#include <bitset>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class input final {
|
||||||
|
input() = delete;
|
||||||
|
public:
|
||||||
|
enum button {
|
||||||
|
UP,
|
||||||
|
DOWN,
|
||||||
|
LEFT,
|
||||||
|
RIGHT,
|
||||||
|
|
||||||
|
_LENGTH // no. of checked inputs
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool held(enum button which) {
|
||||||
|
return _held[which];
|
||||||
|
}
|
||||||
|
static bool pressed(enum button which) {
|
||||||
|
return _pressed[which];
|
||||||
|
}
|
||||||
|
static bool buffered(enum button which) {
|
||||||
|
return _buffered[which];
|
||||||
|
}
|
||||||
|
static void unbuffer(enum button which) {
|
||||||
|
_buffer_mask[which] = false;
|
||||||
|
}
|
||||||
|
static void event(SDL_Event const &evt);
|
||||||
|
static void tickle(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static std::bitset<_LENGTH> _held, _pressed, _buffered, _buffer_mask;
|
||||||
|
|
||||||
|
static struct keyboard {
|
||||||
|
static SDL_Scancode keybinds[_LENGTH][2];
|
||||||
|
static std::bitset<_LENGTH> state[2];
|
||||||
|
} keyboard;
|
||||||
|
|
||||||
|
static struct gamepad {
|
||||||
|
static SDL_JoystickID joystick;
|
||||||
|
static SDL_Gamepad *controller;
|
||||||
|
static SDL_GamepadButton keybinds[_LENGTH][2];
|
||||||
|
static std::bitset<_LENGTH> state[2];
|
||||||
|
} gamepad;
|
||||||
|
|
||||||
|
static struct touch {
|
||||||
|
static void refresh(void);
|
||||||
|
struct position {
|
||||||
|
float x, y;
|
||||||
|
bool active;
|
||||||
|
};
|
||||||
|
static std::vector<struct position> positions;
|
||||||
|
static std::bitset<_LENGTH> state;
|
||||||
|
} touch;
|
||||||
|
};
|
||||||
46
src/main.c++
46
src/main.c++
@ -12,6 +12,7 @@
|
|||||||
#include "batch.h"
|
#include "batch.h"
|
||||||
#include "assets.h++"
|
#include "assets.h++"
|
||||||
#include "main.h++"
|
#include "main.h++"
|
||||||
|
#include "input.h++"
|
||||||
|
|
||||||
#define WINDOW_VIRTUAL 128 // screen buffer, ideally with some padding for the offscreen
|
#define WINDOW_VIRTUAL 128 // screen buffer, ideally with some padding for the offscreen
|
||||||
#define WINDOW_WIDTH 128 // viewport width
|
#define WINDOW_WIDTH 128 // viewport width
|
||||||
@ -34,7 +35,7 @@ static int framebuffer_init(void);
|
|||||||
SDL_AppResult SDL_AppInit(void **, int argc, char **argv) {
|
SDL_AppResult SDL_AppInit(void **, int argc, char **argv) {
|
||||||
clock_t begin = clock();
|
clock_t begin = clock();
|
||||||
|
|
||||||
SDL_Init(SDL_INIT_VIDEO);
|
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD);
|
||||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||||
@ -48,7 +49,7 @@ SDL_AppResult SDL_AppInit(void **, int argc, char **argv) {
|
|||||||
|
|
||||||
int version = gladLoadGLES2((GLADloadfunc) SDL_GL_GetProcAddress);
|
int version = gladLoadGLES2((GLADloadfunc) SDL_GL_GetProcAddress);
|
||||||
if (version == 0) {
|
if (version == 0) {
|
||||||
puts("error: GLES2 failed to initialize");
|
fputs("error: GLES2 failed to initialize\n", stderr);
|
||||||
return SDL_APP_FAILURE;
|
return SDL_APP_FAILURE;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "info: GLES%u.%u\n", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version));
|
fprintf(stderr, "info: GLES%u.%u\n", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version));
|
||||||
@ -98,20 +99,40 @@ SDL_AppResult SDL_AppEvent(void *, SDL_Event *evt) {
|
|||||||
return SDL_APP_SUCCESS;
|
return SDL_APP_SUCCESS;
|
||||||
|
|
||||||
case SDL_EVENT_KEY_DOWN:
|
case SDL_EVENT_KEY_DOWN:
|
||||||
case SDL_EVENT_KEY_UP:
|
if (!evt->key.repeat) {
|
||||||
if (!evt->key.repeat && evt->key.down == true) {
|
|
||||||
if (evt->key.scancode == SDL_SCANCODE_1) {
|
if (evt->key.scancode == SDL_SCANCODE_1) {
|
||||||
square_pixels = !square_pixels;
|
square_pixels = !square_pixels;
|
||||||
} else if (evt->key.scancode == SDL_SCANCODE_2) {
|
} else if (evt->key.scancode == SDL_SCANCODE_2) {
|
||||||
integer_upscale = !integer_upscale;
|
integer_upscale = !integer_upscale;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
// fallthrough
|
||||||
|
case SDL_EVENT_KEY_UP:
|
||||||
case SDL_EVENT_MOUSE_MOTION:
|
case SDL_EVENT_MOUSE_MOTION:
|
||||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||||
case SDL_EVENT_MOUSE_WHEEL:
|
case SDL_EVENT_MOUSE_WHEEL:
|
||||||
|
case SDL_EVENT_FINGER_UP:
|
||||||
|
case SDL_EVENT_FINGER_DOWN:
|
||||||
|
case SDL_EVENT_FINGER_MOTION:
|
||||||
|
case SDL_EVENT_GAMEPAD_ADDED:
|
||||||
|
case SDL_EVENT_GAMEPAD_REMOVED:
|
||||||
|
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
||||||
|
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
||||||
|
case SDL_EVENT_JOYSTICK_AXIS_MOTION:
|
||||||
|
case SDL_EVENT_JOYSTICK_BALL_MOTION:
|
||||||
|
case SDL_EVENT_JOYSTICK_HAT_MOTION:
|
||||||
|
case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
|
||||||
|
case SDL_EVENT_JOYSTICK_BUTTON_UP:
|
||||||
|
case SDL_EVENT_JOYSTICK_ADDED:
|
||||||
|
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
||||||
|
case SDL_EVENT_GAMEPAD_REMAPPED:
|
||||||
|
case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN:
|
||||||
|
case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION:
|
||||||
|
case SDL_EVENT_GAMEPAD_TOUCHPAD_UP:
|
||||||
|
case SDL_EVENT_GAMEPAD_SENSOR_UPDATE:
|
||||||
|
case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED:
|
||||||
|
input::event(*evt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_WINDOW_SHOWN:
|
case SDL_EVENT_WINDOW_SHOWN:
|
||||||
@ -120,24 +141,27 @@ SDL_AppResult SDL_AppEvent(void *, SDL_Event *evt) {
|
|||||||
case SDL_EVENT_WINDOW_MAXIMIZED:
|
case SDL_EVENT_WINDOW_MAXIMIZED:
|
||||||
case SDL_EVENT_WINDOW_RESTORED:
|
case SDL_EVENT_WINDOW_RESTORED:
|
||||||
case SDL_EVENT_WINDOW_MOVED:
|
case SDL_EVENT_WINDOW_MOVED:
|
||||||
break;
|
break; // whatever
|
||||||
|
|
||||||
case SDL_EVENT_WINDOW_RESIZED:
|
case SDL_EVENT_WINDOW_RESIZED:
|
||||||
window_width = evt->window.data1;
|
window_width = evt->window.data1;
|
||||||
window_height = evt->window.data2;
|
window_height = evt->window.data2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_WINDOW_MOUSE_ENTER:
|
case SDL_EVENT_WINDOW_MOUSE_ENTER:
|
||||||
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
|
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
|
||||||
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
||||||
case SDL_EVENT_WINDOW_FOCUS_LOST:
|
case SDL_EVENT_WINDOW_FOCUS_LOST:
|
||||||
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
||||||
break;
|
break; // whatever
|
||||||
|
|
||||||
case SDL_EVENT_WINDOW_EXPOSED:
|
case SDL_EVENT_WINDOW_EXPOSED:
|
||||||
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
||||||
case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED:
|
case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED:
|
||||||
break;
|
break; // whatever these even are
|
||||||
|
|
||||||
case SDL_EVENT_CLIPBOARD_UPDATE:
|
case SDL_EVENT_CLIPBOARD_UPDATE:
|
||||||
break;
|
break; // shush
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "info: unknown event %x\n", evt->type);
|
fprintf(stderr, "info: unknown event %x\n", evt->type);
|
||||||
@ -153,6 +177,8 @@ static struct {
|
|||||||
} fb;
|
} fb;
|
||||||
|
|
||||||
SDL_AppResult SDL_AppIterate(void *) {
|
SDL_AppResult SDL_AppIterate(void *) {
|
||||||
|
input::tickle();
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||||
glViewport(0, 0, WINDOW_VIRTUAL, WINDOW_VIRTUAL);
|
glViewport(0, 0, WINDOW_VIRTUAL, WINDOW_VIRTUAL);
|
||||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user