Skip to content

Studio python module#1464

Merged
glebmish merged 20 commits intoappleseedhq:masterfrom
glebmish:studio-python-module
Jun 22, 2017
Merged

Studio python module#1464
glebmish merged 20 commits intoappleseedhq:masterfrom
glebmish:studio-python-module

Conversation

@glebmish
Copy link
Copy Markdown
Contributor

@glebmish glebmish commented Jun 17, 2017

Created new Python module with appleseed.studio specific binding such as:

  • open_project: opens project in UI by its path
  • save_project: saves project that is currently opened in UI
  • new_project: creates new project and shows it in UI
  • current_project: returns currently opened project as Project object
  • is_project_dirty: returns True if project is changed after last save
  • close_project: closes project and cleans UI


void MainWindow::new_project()
{
if (!can_close_project())
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that in scripting, we always want to close existing project, even if it has unsaved changes.
We should move the can_close_project() test back to the slot.
What do you think?

Copy link
Copy Markdown
Contributor Author

@glebmish glebmish Jun 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree
but maybe we don't want to close project if it's unsaved? Maybe it would be a good idea to introduce force flag here? And if force==false and project is not saved then throw exception

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, good idea.


void MainWindow::build_python_console_panel()
{
PythonInterpreter::instance().set_mainwindow(this);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this to the place where the mainwindow is created?
It's not really related to the python console panel.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure

// appleseed.foundation headers.
#include "foundation/core/concepts/noncopyable.h"

#include "mainwindow/mainwindow.h"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a forward declaration.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that way I need to include mainwindow.h in module.cpp and in every file where I use PythonInterpreter and get MainWindow from it. Is it ok?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is ok. It's more work, but it's better and we already do it everywhere in the rest of the code.

#include <algorithm>
#include <cassert>

#include "python/pythoninterpreter.h"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to the appleseed.studio headers section.

m_project_manager.load_project(filepath.toAscii().constData());
}

void MainWindow::new_project()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe move before open_project() to follow the natural progression: new, open, save, save as, etc.

@@ -85,7 +98,9 @@ PythonInterpreter::PythonInterpreter()
// Imports appleseed module and creates asd alias for it
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update comment now that there are two modules.

@@ -85,7 +98,9 @@ PythonInterpreter::PythonInterpreter()
// Imports appleseed module and creates asd alias for it
// so we can refer to it by both names.
PyRun_SimpleString("import appleseed\n"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All imports first, all namespace aliases next.

studio::PythonInterpreter::instance().get_mainwindow()->open_project(project_path);
}

void new_project()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reorder here too: new_project() first, open_project() second

void execute_command(const char* command);

void redirect_output(OutputRedirector redirector);
void set_mainwindow(MainWindow* mainWindow);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest reordering methods of this class to follow a more logical progression:

instance

set_mainwindow
get_mainwindow

redirect_output

execute_command


void redirect_output(OutputRedirector redirector);
void set_mainwindow(MainWindow* mainWindow);
MainWindow* get_mainwindow();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_mainwindow() should be made const.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't because then I can't use its non-const functions
const MainWindow* PythonInterpreter::get_mainwindow()
{
return mainWindow;
}

PythonInterpreter::instance().get_mainwindow().->open_project();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not talking about returning a const MainWindow*, I'm just saying you should make get_mainwindow() itself const, which isn't the same thing:

MainWindow* get_mainwindow() const;


#include "foundation/platform/python.h"

#include "pythoninterpreter.h"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Headers should be ordered from the most specific first (appleseed.studio headers first in this case) to the most general (typically standard headers). This order was chosen because it helps catching missing header files. Several explanations and details can be found here: https://stackoverflow.com/questions/2762568/c-c-include-file-order-best-practices

Also, add the section comments: "appleseed.studio headers", "appleseed.foundation headers", etc.

namespace bpy = boost::python;
namespace bf = boost::filesystem;

extern "C" void init_appleseedstudio();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this function defined?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is generated by BOOST_PYTHON_MODULE(_appleseedstudio) in module.cpp

m_project_manager.load_project(filepath.toAscii().constData());
}

void MainWindow::open_and_render_project(const QString& filepath, const QString& configuration)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idk if I should expose this

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for now lets not expose it

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought you wanted to remove MainWindow::open_and_render_project()?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it was there before. Should I?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok, my bad :) It's fine then.

return false;
}

bool MainWindow::can_close_project()
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I separated it to use in python module, but don't use it now. Should I revert it?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, if it is unused, lets remove it.

return m_project_manager.get_project();
}

bool MainWindow::is_project_dirty()
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it ok to add this function here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I think so.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe change all appearances of m_project_manager.is_project_dirty in MainWindow on this then?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm really not enthusiastic about it. I see no value in duplicating what the project manager already offers. I'm in favor of removing this method.


MainWindow* mainwindow()
{
return PythonInterpreter::instance().get_mainwindow();
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it have any significant overhead to call for interpreter instance every time I need MainWindow?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really. Scripting is not really about performance and on top of that Python is super slow.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be get_main_window().

}

bool MainWindow::can_close_project()
bool MainWindow::attempt_close_project()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name of this method is misleading: it isn't closing the project, it's just checking if the project can be closed. Maybe ask_can_close_project()? Not ideal but better. Maybe you have a better suggestion? :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will revert it back to old can_close_project function as I don't use separated part anyway


bool MainWindow::can_close_project()
{
return !m_project_manager.is_project_loading() && // Project is not being loaded: no problem
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rewrite as a series of if with early exits as it used to be done. This makes the logic much clearer.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above


// appleseed.studio headers.
#include "mainwindow/mainwindow.h"
#include "pythoninterpreter.h"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be python/pythoninterpreter.h.

using namespace renderer;
using namespace foundation;

MainWindow* mainwindow()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be main_window().


MainWindow* mainwindow()
{
return PythonInterpreter::instance().get_mainwindow();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be get_main_window().

}

void PythonInterpreter::execute_command(const char* command)
void PythonInterpreter::set_mainwindow(MainWindow* window)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be set_main_window().

PythonInterpreter();
~PythonInterpreter();

MainWindow* mainWindow;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be m_main_window.

@dictoon
Copy link
Copy Markdown
Member

dictoon commented Jun 21, 2017

Starts to look pretty awesome!

case QMessageBox::Save:
slot_save_project();
return true;
case QMessageBox::Save:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert indentation for the switch block.

m_project_manager.load_project(filepath.toAscii().constData());
}

void MainWindow::open_and_render_project(const QString& filepath, const QString& configuration)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought you wanted to remove MainWindow::open_and_render_project()?

update_recent_files_menu(filepath);
update_workspace();
}
save_project(filepath);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a regression here: if the user cancelled the Save As dialog, filepath is empty. It appears like this case is no longer handled correctly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there isn't
This check is in save_prject(): if (!filepath.isEmpty())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it isn't in update_recent_files_menu() if I'm not mistaken.

// Destructor.
~MainWindow();

ProjectManager* get_project_manager();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make the method const.

return PythonInterpreter::instance().get_main_window();
}

ProjectManager* project_manager() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move brace to its own line.

return project_manager()->get_project();
}

void save_project(const char* project_path = 0)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer nullptr now that we're using C++11.


void save_project(const char* project_path = 0)
{
if (project_path == 0)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nullptr

namespace bf = boost::filesystem;

// Function prototypes.
extern "C" void init_appleseedstudio();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this function defined?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is generated by BOOST_PYTHON_MODULE(_appleseedstudio) in module.cpp

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. Maybe worth adding a comment to explain this.

@dictoon
Copy link
Copy Markdown
Member

dictoon commented Jun 22, 2017

Almost there! I think you introduced a regression that needs to be fixed, apart from that I've made a handful of minor cosmetics/formatting remarks. Once this is fixed we can merge!

Copy link
Copy Markdown
Member

@dictoon dictoon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect!

glebmish and others added 17 commits June 22, 2017 11:24
* Fix camera movement bug

* Fix line endings

* Fix issues

-Use normalized camera direction
-Simplify expressions
-Cosmetics
CIE 1960 UCS was removed from the colorTransform node together with the
uv related functions. The main purpose here was to get uv chromaticity
coordinates from correlated color temperature, but we ended up using
Klang (2002) CCT to xy method, which dispenses uv and UCS.
HSL, HSV functions were cleaned up and deal correctly with corner cases.
RGB->XYZ->RGB roundtrip, when no space change occurred, using only XYZ
as an intermediary space for transforms, did incur precision loss which
in some cases was enough to set a component as negative (imaginary
color). In the case of HSV, HSL transformations, this resulted in a
visible artifacts. In short, XYZ/RGB have lower bound restricted to 0.
@glebmish glebmish force-pushed the studio-python-module branch from 6388b68 to 53f8638 Compare June 22, 2017 08:25
@glebmish glebmish merged commit 1cdad94 into appleseedhq:master Jun 22, 2017
@glebmish glebmish deleted the studio-python-module branch June 22, 2017 08:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants