add file picking for osx and ios and implement equirectangular import
This commit is contained in:
@@ -26,6 +26,29 @@
|
|||||||
{
|
{
|
||||||
CGLFlushDrawable([glctx CGLContextObj]);
|
CGLFlushDrawable([glctx CGLContextObj]);
|
||||||
}
|
}
|
||||||
|
- (std::string)pick_file
|
||||||
|
{
|
||||||
|
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||||
|
[panel setCanChooseFiles:YES];
|
||||||
|
[panel setCanChooseDirectories:NO];
|
||||||
|
[panel setAllowsMultipleSelection:NO]; // yes if more than one dir is allowed
|
||||||
|
|
||||||
|
NSArray* fileTypes = [NSArray arrayWithObjects:@"png", @"PNG", @"jpg", @"JPG", @"jpeg", nil];
|
||||||
|
[panel setAllowedFileTypes:fileTypes];
|
||||||
|
|
||||||
|
NSInteger clicked = [panel runModal];
|
||||||
|
|
||||||
|
std::string ret;
|
||||||
|
if (clicked == NSFileHandlingPanelOKButton)
|
||||||
|
{
|
||||||
|
for (NSURL *url in [panel URLs])
|
||||||
|
{
|
||||||
|
LOG("selected file: %s", [[url path] cStringUsingEncoding:NSUTF8StringEncoding]);
|
||||||
|
ret = [[url path] cStringUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
- (instancetype)initWithFrame:(NSRect)frameRect
|
- (instancetype)initWithFrame:(NSRect)frameRect
|
||||||
{
|
{
|
||||||
gl_ready = false;
|
gl_ready = false;
|
||||||
|
|||||||
@@ -14,4 +14,5 @@
|
|||||||
- (void)async_lock;
|
- (void)async_lock;
|
||||||
- (void)async_unlock;
|
- (void)async_unlock;
|
||||||
- (void)async_swap;
|
- (void)async_swap;
|
||||||
|
- (std::string)pick_file;
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
#import <GLKit/GLKit.h>
|
#import <GLKit/GLKit.h>
|
||||||
|
|
||||||
@interface GameViewController : GLKViewController <UIKeyInput>
|
@interface GameViewController : GLKViewController <UIKeyInput,UIImagePickerControllerDelegate,UINavigationControllerDelegate>
|
||||||
{
|
{
|
||||||
@public GLKView* glview;
|
@public GLKView* glview;
|
||||||
}
|
}
|
||||||
@@ -17,5 +17,7 @@
|
|||||||
- (void)async_lock;
|
- (void)async_lock;
|
||||||
- (void)async_unlock;
|
- (void)async_unlock;
|
||||||
- (void)async_swap;
|
- (void)async_swap;
|
||||||
|
- (void)pick_photo:(std::function<void(std::string)>) callback;
|
||||||
|
- (void)registerForKeyboardNotifications;
|
||||||
|
- (void)unregisterForKeyboardNotifications;
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -11,6 +11,15 @@
|
|||||||
#import <OpenGLES/ES3/glext.h>
|
#import <OpenGLES/ES3/glext.h>
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
|
|
||||||
|
@interface GameImagePicker : UIImagePickerController
|
||||||
|
{
|
||||||
|
@public std::promise<std::string> promise;
|
||||||
|
@public std::function<void(std::string)> callback;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
@implementation GameImagePicker
|
||||||
|
@end
|
||||||
|
|
||||||
@interface GameViewController () {
|
@interface GameViewController () {
|
||||||
NSLock* gl_lock;
|
NSLock* gl_lock;
|
||||||
}
|
}
|
||||||
@@ -48,6 +57,33 @@ NSThread* lock_thread;
|
|||||||
[self.context presentRenderbuffer:GL_RENDERBUFFER];
|
[self.context presentRenderbuffer:GL_RENDERBUFFER];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)pick_photo:(std::function<void(std::string)>) callback
|
||||||
|
{
|
||||||
|
GameImagePicker *picker = [[GameImagePicker alloc] init];
|
||||||
|
picker.delegate = self;
|
||||||
|
picker.allowsEditing = NO;
|
||||||
|
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
|
||||||
|
picker->callback = callback;
|
||||||
|
[self presentViewController:picker animated:YES completion:NULL];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
|
||||||
|
{
|
||||||
|
NSString *chosenImage = [info[UIImagePickerControllerImageURL] path];
|
||||||
|
GameImagePicker* p = static_cast<GameImagePicker*>(picker);
|
||||||
|
std::string path = [chosenImage cStringUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
p->callback(path);
|
||||||
|
[picker dismissViewControllerAnimated:YES completion:^{
|
||||||
|
[self keyboardWillBeHidden:nil];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
|
||||||
|
{
|
||||||
|
[picker dismissViewControllerAnimated:YES completion:^{
|
||||||
|
[self keyboardWillBeHidden:nil];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)insertText:(NSString *)text
|
- (void)insertText:(NSString *)text
|
||||||
{
|
{
|
||||||
if (const char* cstr = [text cStringUsingEncoding:NSASCIIStringEncoding])
|
if (const char* cstr = [text cStringUsingEncoding:NSASCIIStringEncoding])
|
||||||
@@ -84,6 +120,18 @@ NSThread* lock_thread;
|
|||||||
selector:@selector(keyboardWasHidden:)
|
selector:@selector(keyboardWasHidden:)
|
||||||
name:UIKeyboardDidHideNotification object:nil];
|
name:UIKeyboardDidHideNotification object:nil];
|
||||||
}
|
}
|
||||||
|
- (void)unregisterForKeyboardNotifications
|
||||||
|
{
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||||
|
name:UIKeyboardWillShowNotification object:nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||||
|
name:UIKeyboardWillHideNotification object:nil];
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||||
|
name:UIKeyboardDidShowNotification object:nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||||
|
name:UIKeyboardDidHideNotification object:nil];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)keyboardWillBeShown:(NSNotification*)aNotification
|
- (void)keyboardWillBeShown:(NSNotification*)aNotification
|
||||||
{
|
{
|
||||||
@@ -94,6 +142,7 @@ NSThread* lock_thread;
|
|||||||
{
|
{
|
||||||
App::I.redraw = true;
|
App::I.redraw = true;
|
||||||
App::I.animate = false;
|
App::I.animate = false;
|
||||||
|
[self unregisterForKeyboardNotifications];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when the UIKeyboardDidShowNotification is sent.
|
// Called when the UIKeyboardDidShowNotification is sent.
|
||||||
@@ -233,7 +282,7 @@ NSThread* lock_thread;
|
|||||||
{
|
{
|
||||||
App::I.redraw = true;
|
App::I.redraw = true;
|
||||||
[self resignFirstResponder];
|
[self resignFirstResponder];
|
||||||
[self registerForKeyboardNotifications];
|
//[self registerForKeyboardNotifications];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidLoad
|
- (void)viewDidLoad
|
||||||
|
|||||||
@@ -531,6 +531,10 @@
|
|||||||
<icon icon="page_add" width="20"/>
|
<icon icon="page_add" width="20"/>
|
||||||
<text text="New Pano" margin="0 0 0 5" font-face="arial" font-size="11"/>
|
<text text="New Pano" margin="0 0 0 5" font-face="arial" font-size="11"/>
|
||||||
</button-custom>
|
</button-custom>
|
||||||
|
<button-custom id="file-import" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
|
||||||
|
<icon icon="page_add" width="20"/>
|
||||||
|
<text text="Import" margin="0 0 0 5" font-face="arial" font-size="11"/>
|
||||||
|
</button-custom>
|
||||||
<button-custom id="file-open" text="Menu" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
|
<button-custom id="file-open" text="Menu" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
|
||||||
<icon icon="page_add" width="20"/>
|
<icon icon="page_add" width="20"/>
|
||||||
<text text="Open" margin="0 0 0 5" font-face="arial" font-size="11"/>
|
<text text="Open" margin="0 0 0 5" font-face="arial" font-size="11"/>
|
||||||
|
|||||||
@@ -259,8 +259,8 @@ void App::update(float dt)
|
|||||||
stroke->update_controls();
|
stroke->update_controls();
|
||||||
auto pix = ui::Canvas::I->m_current_brush.m_tip_color;
|
auto pix = ui::Canvas::I->m_current_brush.m_tip_color;
|
||||||
auto hsv = convert_rgb2hsv(glm::vec3(pix[0], pix[1], pix[2]));
|
auto hsv = convert_rgb2hsv(glm::vec3(pix[0], pix[1], pix[2]));
|
||||||
color->m_hue->m_value.y = hsv.x;
|
//color->m_hue->m_value.y = hsv.x;
|
||||||
color->m_quad->m_value = glm::vec2(hsv.y, 1.f - hsv.z);
|
//color->m_quad->m_value = glm::vec2(hsv.y, 1.f - hsv.z);
|
||||||
|
|
||||||
auto observer = [this](Node* n)
|
auto observer = [this](Node* n)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ public:
|
|||||||
struct android_app* and_app;
|
struct android_app* and_app;
|
||||||
struct engine* and_engine;
|
struct engine* and_engine;
|
||||||
#endif
|
#endif
|
||||||
|
void pick_image(std::function<void(std::string path)> callback);
|
||||||
void showKeyboard();
|
void showKeyboard();
|
||||||
void hideKeyboard();
|
void hideKeyboard();
|
||||||
void initLog();
|
void initLog();
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ void App::showKeyboard()
|
|||||||
LOG("show keyboard");
|
LOG("show keyboard");
|
||||||
redraw = true;
|
redraw = true;
|
||||||
#ifdef __IOS__
|
#ifdef __IOS__
|
||||||
|
[ios_view registerForKeyboardNotifications];
|
||||||
[ios_view becomeFirstResponder];
|
[ios_view becomeFirstResponder];
|
||||||
#elif __ANDROID__
|
#elif __ANDROID__
|
||||||
displayKeyboard(and_app, true);
|
displayKeyboard(and_app, true);
|
||||||
@@ -34,11 +35,25 @@ void App::hideKeyboard()
|
|||||||
redraw = true;
|
redraw = true;
|
||||||
#ifdef __IOS__
|
#ifdef __IOS__
|
||||||
[ios_view resignFirstResponder];
|
[ios_view resignFirstResponder];
|
||||||
|
[ios_view unregisterForKeyboardNotifications];
|
||||||
#elif __ANDROID__
|
#elif __ANDROID__
|
||||||
displayKeyboard(and_app, false);
|
displayKeyboard(and_app, false);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void App::pick_image(std::function<void(std::string path)> callback)
|
||||||
|
{
|
||||||
|
redraw = true;
|
||||||
|
#ifdef __IOS__
|
||||||
|
[ios_view pick_photo:callback];
|
||||||
|
#elif __OSX__
|
||||||
|
std::string path = [osx_view pick_file];
|
||||||
|
callback(path);
|
||||||
|
#elif __ANDROID__
|
||||||
|
//displayKeyboard(and_app, false);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool App::mouse_down(int button, float x, float y, float pressure, kEventSource source)
|
bool App::mouse_down(int button, float x, float y, float pressure, kEventSource source)
|
||||||
{
|
{
|
||||||
redraw = true;
|
redraw = true;
|
||||||
|
|||||||
@@ -350,6 +350,13 @@ void App::init_menu_file()
|
|||||||
popup->mouse_release();
|
popup->mouse_release();
|
||||||
popup->destroy();
|
popup->destroy();
|
||||||
};
|
};
|
||||||
|
popup->find<NodeButtonCustom>("file-import")->on_click = [this](Node*) {
|
||||||
|
App::I.pick_image([](std::string path){
|
||||||
|
Canvas::I->import_equirectangular(path);
|
||||||
|
});
|
||||||
|
popup->mouse_release();
|
||||||
|
popup->destroy();
|
||||||
|
};
|
||||||
popup->find<NodeButtonCustom>("file-open")->on_click = [this](Node*) {
|
popup->find<NodeButtonCustom>("file-open")->on_click = [this](Node*) {
|
||||||
dialog_open();
|
dialog_open();
|
||||||
popup->mouse_release();
|
popup->mouse_release();
|
||||||
|
|||||||
@@ -800,6 +800,45 @@ void ui::Canvas::clear_context()
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void ui::Canvas::import_equirectangular(std::string file_path)
|
||||||
|
{
|
||||||
|
std::thread t(&ui::Canvas::import_equirectangular_thread, this, file_path);
|
||||||
|
t.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui::Canvas::import_equirectangular_thread(std::string file_path)
|
||||||
|
{
|
||||||
|
Texture2D tex;
|
||||||
|
gl_state gl;
|
||||||
|
App::I.async_start();
|
||||||
|
gl.save();
|
||||||
|
snap_history({0,1,2,3,4,5});
|
||||||
|
tex.load_file(file_path);
|
||||||
|
ui::Sphere sphere;
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
sphere.create<64, 64>(2.f);
|
||||||
|
draw_objects([&](const glm::mat4& camera, const glm::mat4& proj){
|
||||||
|
m_sampler.bind(0);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
tex.bind();
|
||||||
|
ShaderManager::use(ui::kShader::Texture);
|
||||||
|
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
||||||
|
ShaderManager::u_mat4(kShaderUniform::MVP, proj * camera *
|
||||||
|
glm::eulerAngleY(glm::radians(-90.f)) * glm::scale(glm::vec3(1,-1,1)));
|
||||||
|
sphere.draw_fill();
|
||||||
|
tex.unbind();
|
||||||
|
m_sampler.unbind();
|
||||||
|
});
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
m_dirty_box[i] = glm::vec4(0, 0, m_width, m_height);
|
||||||
|
m_dirty_face[i] = true;
|
||||||
|
}
|
||||||
|
App::I.async_update();
|
||||||
|
gl.restore();
|
||||||
|
App::I.async_end();
|
||||||
|
}
|
||||||
|
|
||||||
void ui::Canvas::export_equirectangular(std::string file_path)
|
void ui::Canvas::export_equirectangular(std::string file_path)
|
||||||
{
|
{
|
||||||
std::thread t(&ui::Canvas::export_equirectangular_thread, this, file_path);
|
std::thread t(&ui::Canvas::export_equirectangular_thread, this, file_path);
|
||||||
|
|||||||
@@ -131,6 +131,8 @@ public:
|
|||||||
void snapshot_restore();
|
void snapshot_restore();
|
||||||
void snap_history(const std::vector<int>& planes);
|
void snap_history(const std::vector<int>& planes);
|
||||||
void clear_context();
|
void clear_context();
|
||||||
|
void import_equirectangular(std::string file_path);
|
||||||
|
void import_equirectangular_thread(std::string file_path);
|
||||||
void export_equirectangular(std::string file_path);
|
void export_equirectangular(std::string file_path);
|
||||||
void export_equirectangular_thread(std::string file_path);
|
void export_equirectangular_thread(std::string file_path);
|
||||||
void export_anim(std::string data_path);
|
void export_anim(std::string data_path);
|
||||||
|
|||||||
@@ -23,6 +23,15 @@ bool Image::load(std::string filename)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Image::load_file(std::string filename)
|
||||||
|
{
|
||||||
|
stbi_set_flip_vertically_on_load(false);
|
||||||
|
uint8_t* buffer = stbi_load(filename.c_str(), &width, &height, nullptr, 4);
|
||||||
|
comp = 4;
|
||||||
|
m_data = std::unique_ptr<uint8_t[]>(buffer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Image::flip()
|
void Image::flip()
|
||||||
{
|
{
|
||||||
auto flipped = std::make_unique<uint8_t[]>(width*height*4);
|
auto flipped = std::make_unique<uint8_t[]>(width*height*4);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ public:
|
|||||||
int height = 0;
|
int height = 0;
|
||||||
int comp = 4;
|
int comp = 4;
|
||||||
bool load(std::string filename);
|
bool load(std::string filename);
|
||||||
|
bool load_file(std::string filename);
|
||||||
const uint8_t* data() const { return m_data.get(); }
|
const uint8_t* data() const { return m_data.get(); }
|
||||||
int size() const { return width * height * comp; }
|
int size() const { return width * height * comp; }
|
||||||
void create(int w, int h)
|
void create(int w, int h)
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ void NodeCanvas::draw()
|
|||||||
ui::ShaderManager::u_int(kShaderUniform::TexStroke, 1);
|
ui::ShaderManager::u_int(kShaderUniform::TexStroke, 1);
|
||||||
ui::ShaderManager::u_int(kShaderUniform::TexMask, 2);
|
ui::ShaderManager::u_int(kShaderUniform::TexMask, 2);
|
||||||
ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity);
|
ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity);
|
||||||
ui::ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[m_canvas->m_current_layer_idx].m_alpha_locked);
|
ui::ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[layer_index].m_alpha_locked);
|
||||||
ui::ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active);
|
ui::ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active);
|
||||||
ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
|
ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
@@ -151,7 +151,7 @@ void NodeCanvas::draw()
|
|||||||
ui::ShaderManager::u_int(kShaderUniform::TexMask, 2);
|
ui::ShaderManager::u_int(kShaderUniform::TexMask, 2);
|
||||||
//ui::ShaderManager::u_int(kShaderUniform::TexStencil, 3);
|
//ui::ShaderManager::u_int(kShaderUniform::TexStencil, 3);
|
||||||
ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity);
|
ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity);
|
||||||
ui::ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[m_canvas->m_current_layer_idx].m_alpha_locked);
|
ui::ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[layer_index].m_alpha_locked);
|
||||||
ui::ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active);
|
ui::ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active);
|
||||||
ui::ShaderManager::u_int(kShaderUniform::BlendMode, m_canvas->m_current_stroke->m_brush.m_blend_mode);
|
ui::ShaderManager::u_int(kShaderUniform::BlendMode, m_canvas->m_current_stroke->m_brush.m_blend_mode);
|
||||||
ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
|
ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
|
||||||
|
|||||||
@@ -94,6 +94,6 @@ void NodeColorQuad::draw()
|
|||||||
using namespace ui;
|
using namespace ui;
|
||||||
ui::ShaderManager::use(kShader::ColorQuad);
|
ui::ShaderManager::use(kShader::ColorQuad);
|
||||||
ui::ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
|
ui::ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
|
||||||
ui::ShaderManager::u_vec4(kShaderUniform::Col, m_color);
|
ui::ShaderManager::u_vec4(kShaderUniform::Col, glm::vec4(convert_rgb2hsv(glm::vec3(m_color)), 1));
|
||||||
m_plane.draw_fill();
|
m_plane.draw_fill();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <future>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|||||||
@@ -456,6 +456,37 @@ void Slice9::create_impl(float w, float h, float r, float tr, GLushort *idx, Sha
|
|||||||
*idx++ = 12; // D
|
*idx++ = 12; // D
|
||||||
*idx++ = 0; // A
|
*idx++ = 0; // A
|
||||||
}
|
}
|
||||||
|
void Sphere::create_impl(int rings, int sectors, float radius, GLushort *idx, Shape::vertex_t *vertices)
|
||||||
|
{
|
||||||
|
count[0] = rings * sectors * 6;
|
||||||
|
count[1] = 0;
|
||||||
|
ioff[0] = (GLvoid*)0;
|
||||||
|
ioff[1] = (GLvoid*)0;
|
||||||
|
|
||||||
|
float const R = 1.f / (float)(rings-1);
|
||||||
|
float const S = 1.f / (float)(sectors-1);
|
||||||
|
int r, s;
|
||||||
|
|
||||||
|
auto v = vertices;
|
||||||
|
for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) {
|
||||||
|
float const y = (float)sin( -M_PI_2 + M_PI * r * R );
|
||||||
|
float const x = (float)cos(2*M_PI * s * S) * (float)sin( M_PI * r * R );
|
||||||
|
float const z = (float)sin(2*M_PI * s * S) * (float)sin( M_PI * r * R );
|
||||||
|
|
||||||
|
*v++ = { glm::vec4(x, y, z, 1) * radius, glm::vec2(s*S, r*R) };
|
||||||
|
}
|
||||||
|
|
||||||
|
auto i = idx;
|
||||||
|
for(r = 0; r < rings-1; r++) for(s = 0; s < sectors-1; s++) {
|
||||||
|
*i++ = r * sectors + s;
|
||||||
|
*i++ = r * sectors + (s+1);
|
||||||
|
*i++ = (r+1) * sectors + (s+1);
|
||||||
|
|
||||||
|
*i++ = r * sectors + s;
|
||||||
|
*i++ = (r+1) * sectors + (s+1);
|
||||||
|
*i++ = (r+1) * sectors + s;
|
||||||
|
}
|
||||||
|
}
|
||||||
void ui::LineSegment::update_vertices(const glm::vec4 data[2])
|
void ui::LineSegment::update_vertices(const glm::vec4 data[2])
|
||||||
{
|
{
|
||||||
static vertex_t vertices[2];
|
static vertex_t vertices[2];
|
||||||
|
|||||||
@@ -194,4 +194,18 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Sphere : public Shape
|
||||||
|
{
|
||||||
|
void create_impl(int rings, int sectors, float radius, GLushort* idx, vertex_t* vertices);
|
||||||
|
public:
|
||||||
|
template<int rings, int sectors>
|
||||||
|
bool create(float radius)
|
||||||
|
{
|
||||||
|
static GLushort idx[rings * sectors * 6];
|
||||||
|
static vertex_t vertices[rings * sectors];
|
||||||
|
create_impl(rings, sectors, radius, idx, vertices);
|
||||||
|
return create_buffers(idx, vertices, sizeof(idx), sizeof(vertices));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,16 @@ bool Texture2D::load(std::string filename)
|
|||||||
return false;
|
return false;
|
||||||
return create(img);
|
return create(img);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Texture2D::load_file(std::string filename)
|
||||||
|
{
|
||||||
|
LOG("load texture %s", filename.c_str());
|
||||||
|
ui::Image img;
|
||||||
|
if (!img.load_file(filename))
|
||||||
|
return false;
|
||||||
|
return create(img);
|
||||||
|
}
|
||||||
|
|
||||||
void Texture2D::update(const uint8_t* data)
|
void Texture2D::update(const uint8_t* data)
|
||||||
{
|
{
|
||||||
bind();
|
bind();
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ public:
|
|||||||
bool create(const ui::Image& img);
|
bool create(const ui::Image& img);
|
||||||
void assign(GLuint tex, int w = -1, int h = -1, GLuint internal_format = GL_RGBA8, GLuint format = GL_RGBA);
|
void assign(GLuint tex, int w = -1, int h = -1, GLuint internal_format = GL_RGBA8, GLuint format = GL_RGBA);
|
||||||
bool load(std::string filename);
|
bool load(std::string filename);
|
||||||
|
bool load_file(std::string filename);
|
||||||
void destroy() { if (m_tex) LOG("TEX destroy %d", m_tex); glDeleteTextures(1, &m_tex); }
|
void destroy() { if (m_tex) LOG("TEX destroy %d", m_tex); glDeleteTextures(1, &m_tex); }
|
||||||
void bind() const { glBindTexture(GL_TEXTURE_2D, m_tex); }
|
void bind() const { glBindTexture(GL_TEXTURE_2D, m_tex); }
|
||||||
void unbind() const { glBindTexture(GL_TEXTURE_2D, 0); }
|
void unbind() const { glBindTexture(GL_TEXTURE_2D, 0); }
|
||||||
|
|||||||
Reference in New Issue
Block a user