353 lines
7.9 KiB
C++
353 lines
7.9 KiB
C++
/* SPDX-License-Identifier: Apache-2.0
|
|
* Copyright 2011-2022 Blender Foundation */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "app/opengl/window.h"
|
|
|
|
#include "util/string.h"
|
|
#include "util/thread.h"
|
|
#include "util/time.h"
|
|
#include "util/version.h"
|
|
|
|
#include <GL/glew.h>
|
|
#include <SDL.h>
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
/* structs */
|
|
|
|
struct Window {
|
|
WindowInitFunc initf = nullptr;
|
|
WindowExitFunc exitf = nullptr;
|
|
WindowResizeFunc resize = nullptr;
|
|
WindowDisplayFunc display = nullptr;
|
|
WindowKeyboardFunc keyboard = nullptr;
|
|
WindowMotionFunc motion = nullptr;
|
|
|
|
bool first_display = true;
|
|
bool redraw = false;
|
|
|
|
int mouseX = 0, mouseY = 0;
|
|
int mouseBut0 = 0, mouseBut2 = 0;
|
|
|
|
int width = 0, height = 0;
|
|
|
|
SDL_Window *window = nullptr;
|
|
SDL_GLContext gl_context = nullptr;
|
|
thread_mutex gl_context_mutex;
|
|
} V;
|
|
|
|
/* public */
|
|
|
|
static void window_display_text(int x, int y, const char *text)
|
|
{
|
|
/* Not currently supported, need to add text rendering support. */
|
|
#if 0
|
|
const char *c;
|
|
|
|
glRasterPos3f(x, y, 0);
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
|
|
printf("display %s\n", text);
|
|
|
|
for (c = text; *c != '\0'; c++) {
|
|
const uint8_t *bitmap = helvetica10_character_map[*c];
|
|
glBitmap(bitmap[0],
|
|
helvetica10_height,
|
|
helvetica10_x_offset,
|
|
helvetica10_y_offset,
|
|
bitmap[0],
|
|
0.0f,
|
|
bitmap + 1);
|
|
}
|
|
#else
|
|
static string last_text = "";
|
|
|
|
if (text != last_text) {
|
|
printf("%s\n", text);
|
|
last_text = text;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void window_display_info(const char *info)
|
|
{
|
|
const int height = 20;
|
|
|
|
#if 0
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glColor4f(0.1f, 0.1f, 0.1f, 0.8f);
|
|
glRectf(0.0f, V.height - height, V.width, V.height);
|
|
glDisable(GL_BLEND);
|
|
|
|
glColor3f(0.5f, 0.5f, 0.5f);
|
|
#endif
|
|
|
|
window_display_text(10, 7 + V.height - height, info);
|
|
|
|
#if 0
|
|
glColor3f(1.0f, 1.0f, 1.0f);
|
|
#endif
|
|
}
|
|
|
|
void window_display_help()
|
|
{
|
|
const int w = (int)((float)V.width / 1.15f);
|
|
const int h = (int)((float)V.height / 1.15f);
|
|
|
|
const int x1 = (V.width - w) / 2;
|
|
#if 0
|
|
const int x2 = x1 + w;
|
|
#endif
|
|
|
|
const int y1 = (V.height - h) / 2;
|
|
const int y2 = y1 + h;
|
|
|
|
#if 0
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glColor4f(0.5f, 0.5f, 0.5f, 0.8f);
|
|
glRectf(x1, y1, x2, y2);
|
|
glDisable(GL_BLEND);
|
|
|
|
glColor3f(0.8f, 0.8f, 0.8f);
|
|
#endif
|
|
|
|
string info = string("Cycles Renderer ") + CYCLES_VERSION_STRING;
|
|
|
|
window_display_text(x1 + 20, y2 - 20, info.c_str());
|
|
window_display_text(x1 + 20, y2 - 40, "(C) 2011-2016 Blender Foundation");
|
|
window_display_text(x1 + 20, y2 - 80, "Controls:");
|
|
window_display_text(x1 + 20, y2 - 100, "h: Info/Help");
|
|
window_display_text(x1 + 20, y2 - 120, "r: Reset");
|
|
window_display_text(x1 + 20, y2 - 140, "p: Pause");
|
|
window_display_text(x1 + 20, y2 - 160, "esc: Cancel");
|
|
window_display_text(x1 + 20, y2 - 180, "q: Quit program");
|
|
|
|
window_display_text(x1 + 20, y2 - 210, "i: Interactive mode");
|
|
window_display_text(x1 + 20, y2 - 230, "Left mouse: Move camera");
|
|
window_display_text(x1 + 20, y2 - 250, "Right mouse: Rotate camera");
|
|
window_display_text(x1 + 20, y2 - 270, "W/A/S/D: Move camera");
|
|
window_display_text(x1 + 20, y2 - 290, "0/1/2/3: Set max bounces");
|
|
|
|
#if 0
|
|
glColor3f(1.0f, 1.0f, 1.0f);
|
|
#endif
|
|
}
|
|
|
|
static void window_display()
|
|
{
|
|
if (V.first_display) {
|
|
if (V.initf) {
|
|
V.initf();
|
|
}
|
|
if (V.exitf) {
|
|
atexit(V.exitf);
|
|
}
|
|
|
|
V.first_display = false;
|
|
}
|
|
|
|
window_opengl_context_enable();
|
|
|
|
glViewport(0, 0, V.width, V.height);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
|
|
glClearColor(0.05f, 0.05f, 0.05f, 0.0f);
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
glOrtho(0, V.width, 0, V.height, -1, 1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
|
|
glRasterPos3f(0, 0, 0);
|
|
|
|
if (V.display)
|
|
V.display();
|
|
|
|
SDL_GL_SwapWindow(V.window);
|
|
window_opengl_context_disable();
|
|
}
|
|
|
|
static void window_reshape(int width, int height)
|
|
{
|
|
if (V.width != width || V.height != height) {
|
|
if (V.resize) {
|
|
V.resize(width, height);
|
|
}
|
|
}
|
|
|
|
V.width = width;
|
|
V.height = height;
|
|
}
|
|
|
|
static bool window_keyboard(unsigned char key)
|
|
{
|
|
if (V.keyboard)
|
|
V.keyboard(key);
|
|
|
|
if (key == 'q') {
|
|
if (V.exitf)
|
|
V.exitf();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static void window_mouse(int button, int state, int x, int y)
|
|
{
|
|
if (button == SDL_BUTTON_LEFT) {
|
|
if (state == SDL_MOUSEBUTTONDOWN) {
|
|
V.mouseX = x;
|
|
V.mouseY = y;
|
|
V.mouseBut0 = 1;
|
|
}
|
|
else if (state == SDL_MOUSEBUTTONUP) {
|
|
V.mouseBut0 = 0;
|
|
}
|
|
}
|
|
else if (button == SDL_BUTTON_RIGHT) {
|
|
if (state == SDL_MOUSEBUTTONDOWN) {
|
|
V.mouseX = x;
|
|
V.mouseY = y;
|
|
V.mouseBut2 = 1;
|
|
}
|
|
else if (state == SDL_MOUSEBUTTONUP) {
|
|
V.mouseBut2 = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void window_motion(int x, int y)
|
|
{
|
|
const int but = V.mouseBut0 ? 0 : 2;
|
|
const int distX = x - V.mouseX;
|
|
const int distY = y - V.mouseY;
|
|
|
|
if (V.motion)
|
|
V.motion(distX, distY, but);
|
|
|
|
V.mouseX = x;
|
|
V.mouseY = y;
|
|
}
|
|
|
|
bool window_opengl_context_enable()
|
|
{
|
|
V.gl_context_mutex.lock();
|
|
SDL_GL_MakeCurrent(V.window, V.gl_context);
|
|
return true;
|
|
}
|
|
|
|
void window_opengl_context_disable()
|
|
{
|
|
SDL_GL_MakeCurrent(V.window, nullptr);
|
|
V.gl_context_mutex.unlock();
|
|
}
|
|
|
|
void window_main_loop(const char *title,
|
|
int width,
|
|
int height,
|
|
WindowInitFunc initf,
|
|
WindowExitFunc exitf,
|
|
WindowResizeFunc resize,
|
|
WindowDisplayFunc display,
|
|
WindowKeyboardFunc keyboard,
|
|
WindowMotionFunc motion)
|
|
{
|
|
V.width = width;
|
|
V.height = height;
|
|
V.first_display = true;
|
|
V.redraw = false;
|
|
V.initf = initf;
|
|
V.exitf = exitf;
|
|
V.resize = resize;
|
|
V.display = display;
|
|
V.keyboard = keyboard;
|
|
V.motion = motion;
|
|
|
|
SDL_Init(SDL_INIT_VIDEO);
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
|
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
|
|
V.window = SDL_CreateWindow(title,
|
|
SDL_WINDOWPOS_UNDEFINED,
|
|
SDL_WINDOWPOS_UNDEFINED,
|
|
width,
|
|
height,
|
|
SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
|
|
if (V.window == nullptr) {
|
|
fprintf(stderr, "Failed to create window: %s\n", SDL_GetError());
|
|
return;
|
|
}
|
|
|
|
SDL_RaiseWindow(V.window);
|
|
|
|
V.gl_context = SDL_GL_CreateContext(V.window);
|
|
glewInit();
|
|
SDL_GL_MakeCurrent(V.window, nullptr);
|
|
|
|
window_reshape(width, height);
|
|
window_display();
|
|
|
|
while (true) {
|
|
bool quit = false;
|
|
SDL_Event event;
|
|
while (!quit && SDL_PollEvent(&event)) {
|
|
if (event.type == SDL_TEXTINPUT) {
|
|
quit = window_keyboard(event.text.text[0]);
|
|
}
|
|
else if (event.type == SDL_MOUSEMOTION) {
|
|
window_motion(event.motion.x, event.motion.y);
|
|
}
|
|
else if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) {
|
|
window_mouse(event.button.button, event.button.state, event.button.x, event.button.y);
|
|
}
|
|
else if (event.type == SDL_WINDOWEVENT) {
|
|
if (event.window.event == SDL_WINDOWEVENT_RESIZED ||
|
|
event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
|
|
window_reshape(event.window.data1, event.window.data2);
|
|
}
|
|
}
|
|
else if (event.type == SDL_QUIT) {
|
|
if (V.exitf) {
|
|
V.exitf();
|
|
}
|
|
quit = true;
|
|
}
|
|
}
|
|
|
|
if (quit) {
|
|
break;
|
|
}
|
|
|
|
if (V.redraw) {
|
|
V.redraw = false;
|
|
window_display();
|
|
}
|
|
|
|
SDL_WaitEventTimeout(NULL, 100);
|
|
}
|
|
|
|
SDL_GL_DeleteContext(V.gl_context);
|
|
SDL_DestroyWindow(V.window);
|
|
SDL_Quit();
|
|
}
|
|
|
|
void window_redraw()
|
|
{
|
|
V.redraw = true;
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|