blob: 148468c580e859fa146585299f3d8b200c7ec38c [file] [log] [blame]
<!doctype html>
<html class="no-js" lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Writing POV-Ray Support for NetBeans II—Project Type Design</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Writing POV-Ray Support for NetBeans II—Project Type Design - Apache NetBeans">
<meta name="author" content="Apache NetBeans">
<meta name="description" content="Writing POV-Ray Support for NetBeans II—Project Type Design - Apache NetBeans">
<meta name="keywords" content="Apache NetBeans Platform, Platform Tutorials, Writing POV-Ray Support for NetBeans II—Project Type Design">
<meta name="generator" content="Apache NetBeans">
<link rel="stylesheet" href="../../../../_/css/font-awesome.min.css">
<link rel="alternate" type="application/atom+xml" title="Apache NetBeans Blog" href="https://netbeans.apache.org/blogs/atom" />
<link rel="stylesheet" href="../../../../_/css/highlightjs/default.min.css">
<link rel="stylesheet" href="../../../../_/css/netbeans.css">
<link rel="apple-touch-icon" sizes="180x180" href="../../../../_/images/fav/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../../../_/images/fav/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../../../_/images/fav/favicon-16x16.png">
<link rel="manifest" href="../../../../_/images/fav/site.webmanifest">
<link rel="mask-icon" href="../../../../_/images/fav/safari-pinned-tab.svg" color="#5bbad5">
<meta name="msapplication-TileColor" content="#ffc40d">
<meta name="theme-color" content="#ffffff">
<link href="../../../../_/css/font-open-sans.css" rel="stylesheet">
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
-->
</head>
<body>
<div class="title-bar" data-responsive-toggle="responsive-menu" data-hide-for="medium">
<button type="button" data-toggle="responsive-menu"><i style='font-size: 32px; color: #fff; padding: 8px' class='fa fa-bars'></i></button>
<div class="title-bar-title">Apache NetBeans</div>
</div>
<div class="top-bar" id="responsive-menu">
<div class='top-bar-left'>
<a class='title' href="../../../../index.html"><img src='../../../../_/images/apache-netbeans.svg' style='padding: 8px; height: 48px;'> Apache NetBeans</a>
</div>
<div class="top-bar-right">
<ul class="vertical medium-horizontal menu" data-responsive-menu="drilldown medium-dropdown">
<li> <input id="search-input" type="text" placeholder="Search the docs"> </li>
<li> <a href="../../../../front/main/community">Community</a> </li>
<li> <a href="../../../../front/main/participate">Participate</a> </li>
<li> <a href="../../../../front/main/blogs">Blog</a></li>
<li> <a href="../../../../front/main/help">Get Help</a> </li>
<li> <a href="https://plugins.netbeans.apache.org/">Plugins</a> </li>
<li> <a href="../../../../front/main/download">Download</a> </li>
</ul>
</div>
</div>
<!-- src/templates/news -->
<section class="hero news alternate">
<div class='grid-container'>
<div class='cell'>
<div class="annotation">Latest release</div>
<h1>Apache NetBeans 28</h1>
<p><a class="button success" href="../../../../front/main/download/nb28">Download</a></p>
</div>
</div>
</section>
<div class='grid-container main-content tutorial'>
<h1 class="sect0">Writing POV-Ray Support for NetBeans II—Project Type Design</h1>
<div class="sectionbody">
<div class="admonitionblock note">
<table>
<tbody><tr>
<td class="icon"><i class="fa icon-note" title="Note"></i></td>
<td class="content">This tutorial needs a review.
You can <a href="https://github.com/apache/netbeans-antora-tutorials/edit/main/modules/ROOT/pages/tutorials/nbm-povray-2.adoc" title="Edit this tutorial in github">edit it in GitHub </a>
following these <a href="../../../../tutorial/main/kb/docs/contributing">contribution guidelines.</a></td>
</tr></tbody>
</table>
</div>
</div>
<div id="toc" class="toc">
<div id="toctitle"></div>
<ul class="sectlevel1">
<li><a href="#_design_and_coupling">Design and Coupling</a></li>
<li><a href="#_design_choicesdont_try_to_save_the_world">Design Choices—Don&#8217;t Try to Save the World</a></li>
<li><a href="#_physical_structure_of_a_pov_ray_project">[[Physical Structure of a POV-Ray Project]]</a></li>
<li><a href="#_coupling_between_pov_ray_files_and_pov_ray_project">Coupling Between POV-Ray Files and POV-Ray Project</a></li>
<li><a href="#_summary">Summary</a></li>
</ul>
</div>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>In this part of the tutorial, we will walk through how to create a basic project type. It will be a project type that supports building 3D graphics scenes using <a href="http://povray.org">POV-Ray</a>'s scene language, and eventually, rendering them as images and displaying the result in NetBeans.</p>
</div>
<div class="paragraph">
<p>It is assumed you have completed the steps in the <a href="../nbm-povray-1/" class="xref page">previous tutorial</a> for creating basic POV-Ray support.</p>
</div>
<div class="paragraph">
<p>This tutorial will go through the up-front design and thinking through needed to successfully implement a project type that will serve its users well. The subsequent tutorial walks through the implementation of the basic project.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_design_and_coupling"><a class="anchor" href="#_design_and_coupling"></a>Design and Coupling</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A NetBeans project is a directory on disk; typically there is some signature, such as having a subdirectory with a specific name, which identifies that directory as being a project.</p>
</div>
<div class="paragraph">
<p>The major requirement of identifying a folder as being a project is that the test fail quickly—the code that determines that a folder is <em>not</em> a project must complete very quickly, because it is going to be called once for every folder visible in the file chooser that lets users open projects. We will stick with what works, and use a specific subdirectory name to identify our POV-Ray projects.</p>
</div>
<div class="paragraph">
<p>Most Project types in NetBeans use <a href="https://ant.apache.org">Apache Ant</a> as their build infrastructure, and there are APIs for building Ant-based projects. This example does <em>not</em> use Ant, but implements a simple basic project type. Even if you know you will use Ant, you will encounter all of the concepts presented here in implementing an Ant-based project.</p>
</div>
<div class="paragraph">
<p>Notice that we implemented support for <code>.pov</code> and <code>.inc</code> files in a <a href="../nbm-povray-1/" class="xref page">separate module</a>. Design-wise this makes sense—data recognition and project types are orthagonal—and it provides a good demonstration of how to do loose coupling between modules.</p>
</div>
<div class="paragraph">
<p>So at this point we need to think about what we&#8217;re designing, what functionality belongs to which module, and what will serve our users' needs best. Before we do any coding, some design has to happen. Here&#8217;s what we know about POV-Ray and its usage patterns:</p>
</div>
<div class="olist arabic">
<ol class="arabic" start="1">
<li>
<p>POV-Ray has a scene language, and it "compiles" textual <code>.pov</code> files down into image files.</p>
</li>
</ol>
</div>
<div class="olist arabic">
<ol class="arabic" start="2">
<li>
<p>A <code>.pov</code> file can reference other files, which typically get the extension <code>.inc</code>.</p>
</li>
</ol>
</div>
<div class="olist arabic">
<ol class="arabic" start="3">
<li>
<p>POV-Ray has a huge number of options such as antialiasing, jitter, output image size, quality, number of reflections, animation clock.</p>
</li>
</ol>
</div>
<div class="olist arabic">
<ol class="arabic" start="4">
<li>
<p>Users will render small test versions of a scene at low quality to check their work as they go; large, high quality renders can take a long time.</p>
</li>
</ol>
</div>
<div class="olist arabic">
<ol class="arabic" start="5">
<li>
<p>Typically the user knows the size and aspect ratio they&#8217;ll want for the final output, but that&#8217;s also <em>not</em> what most renders will use.</p>
</li>
</ol>
</div>
<div class="olist arabic">
<ol class="arabic" start="6">
<li>
<p>To save rendering time while working, a user may split individual objects from a scene into separate files and render them individually as they work.</p>
</li>
</ol>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_design_choicesdont_try_to_save_the_world"><a class="anchor" href="#_design_choicesdont_try_to_save_the_world"></a>Design Choices—Don&#8217;t Try to Save the World</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The biggest killer of projects is trying to "save the world" - trying to provide every combination of every possible option to the user, such that the user is confronted with a bewildering array of choices when most of the time they want to do something very simple. Trying to support every imaginable permutation of anything leads to projects which are permanently six months from completion. So we need to limit the scope while providing value to the user. But we also want to keep power users happy and give them the ability to do what they need to do. So we have some choices to make, and some hard thinking to do about what is the right UI to balance the power of POV-Ray with the need to keep things simple and easy to use for beginners.</p>
</div>
<div class="paragraph">
<p>The first question, from item 1, is, which module owns the rendering infrastructure? Well, when you render an image, you need a place to put it. A project owns a directory and its subdirectories. So we&#8217;ll make an executive decision right now that we don&#8217;t render a random <code>.pov</code> file on disk—it must belong to a project which can provide a place to put the result. So the code that actually calls out to POV-Ray will be part of the project support module, not the file support module.</p>
</div>
<div class="paragraph">
<p>A follow-on to this is, should it be possible to render absolutely any <code>.pov</code> or <code>.inc</code> file? Probably yes, due to fact 6—but we&#8217;ll only do that if it belongs to a project.</p>
</div>
<div class="paragraph">
<p>Do we want to provide structure (subfolders, etc.) in POV-Ray projects? It would probably be nice for the future, but to keep the scope of things manageable, we&#8217;re not going to do that now. In practice, POV-Ray projects can be just as messy as projects written in C, with source files scattered hither and yon. We are not going to try to solve all the world&#8217;s problems here; but neither are we going to impose our own idea of what a well structured POV-Ray project looks like on the user.</p>
</div>
<div class="paragraph">
<p>How many of the myriad command-line options that POV-Ray supports should we expose the user to? The real usage pattern here is that, for test renders, any of a few sets of standard settings will do for almost all cases. So we will provide a set of standard resolutions like 320x200, 640x480, 1024x768. Those settings will be unmodifiable. But, associated with each project will be a set of <em>production settings</em>, which are saved with the project, are shareable and go with the project wherever it goes. We will provide a basic GUI customizer for the production settings. It will not cover every possible setting POV-Ray has—<em>however</em>, the customizer will be writing into the project&#8217;s <code>project.properties</code> file - and a power user can edit in their own settings to do anything they want, so the full power of POV-Ray stays available to power users—any desired line switch can be encoded into the project&#8217;s properties file and end up passed on the command line to POV-Ray.</p>
</div>
<div class="paragraph">
<p>Because of item 6, we know there can be multiple files in a project, but only one is the master scene that is the final output of the project. So we will give our projects the concept of a <em>main file</em> which is what gets rendered when they invoke Build, and we&#8217;ll need a UI to select which file it is.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_physical_structure_of_a_pov_ray_project"><a class="anchor" href="#_physical_structure_of_a_pov_ray_project"></a>[[Physical Structure of a POV-Ray Project]]</h2>
<div class="sectionbody">
<div class="paragraph">
<p>We also need to make some decisions about what will be stored on disk and where. We know that projects typically have Build and Clean actions, and these will be useful for POV-Ray projects as well. Where should scene files go? Well, we want to keep some flexibility for future versions, so we don&#8217;t want them in the root directory of our projects—we&#8217;ll create a <code>scenes/</code> folder for them.</p>
</div>
<div class="paragraph">
<p>We also know we will end up with image files from rendering. The Clean operation will be much less complex to implement if it just means deleting a directory. And the UI will be less cluttered if we put images in their own directory, so rendered images will go in an <code>images/</code> subdirectory of the project. The project UI won&#8217;t even show the <code>images/</code> directory—you&#8217;ll just right-click a scene file and select <em>View</em>, to render and show a single file, or build the project to show the "main file". As with compiling, we will do a date check to see if the source file is newer than the image file, and if so, render it again.</p>
</div>
<div class="paragraph">
<p>We also know we need to use a subdirectory to identify our project type, and to store configuration data that should be saved, such as which file is the main file and what are the production renderer settings. So we&#8217;ll decide that every POV-Ray project will have a <code>pvproject</code> subdirectory, and in that directory will be a <code>properties</code> file. So on disk, a typical POV-Ray project will look like:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Wonderland/</p>
</li>
<li>
<p>images/</p>
</li>
<li>
<p>Wonderland.png</p>
</li>
<li>
<p>pvproject/</p>
</li>
<li>
<p>project.properties</p>
</li>
<li>
<p>scenes/</p>
</li>
<li>
<p>Alice.inc</p>
</li>
<li>
<p><strong>Wonderland.pov</strong></p>
</li>
<li>
<p>LookingGlass.inc</p>
</li>
<li>
<p>MadQueen.inc</p>
</li>
<li>
<p>MockTurtle.inc</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_coupling_between_pov_ray_files_and_pov_ray_project"><a class="anchor" href="#_coupling_between_pov_ray_files_and_pov_ray_project"></a>Coupling Between POV-Ray Files and POV-Ray Project</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Typically a user is going to be dealing with files, and we already decided that a user should be able to render any file in a project; and we know we are going to have to give the user the ability to pick which file is the main file for a project. That means our <code>Node`s for `.pov</code> files will need to have <code>Action`s that will be invoking rendering and main-file-setting code that belongs to the project module, not to their module. So we know we that the project module will need to expose some API for doing these things, and the `Node</code> of a POV-Ray file will need to be able to find the project that owns it and call this code. But if a <code>.pov</code> is orphaned on disk, or is inside, say, a J2EE project for some reason, it must fail gracefully.</p>
</div>
<div class="paragraph">
<p>This gives a great opportunity to demonstrate how loose coupling between modules is done. There are two simple mechanisms that will allow us to easily do this: The first is <code>FileOwnerQuery</code>—this is a class from the <code>Project</code> module, which allows one to find out what project owns any file. The second is that <code>Project</code>, the interface we implement to create our project type, has a method <code>getLookup()</code>. So we will provide some interfaces in the POV-Ray project type which we&#8217;ll make available as API. When a node finds out what project its file belongs to, it can simply request the implementation of one of those interfaces. If it gets non-null, it can call the rendering or main-file-setting functionality; if it gets null, or the project is null, those actions will just be disabled.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_summary"><a class="anchor" href="#_summary"></a>Summary</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Design is an inescapable first-step in developing modules. It pays to think hard about what functionality belongs where, and what the user experience should be before starting to code.</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="../nbm-povray-3/" class="xref page">Next: Implementing POV-Ray Project Support</a>*</p>
</li>
</ul>
</div>
</div>
</div>
<section class='tools'>
<ul class="menu align-center">
<li><a title="Facebook" href="https://www.facebook.com/NetBeans"><i class="fa fa-md fa-facebook"></i></a></li>
<li><a title="Twitter" href="https://twitter.com/netbeans"><i class="fa fa-md fa-twitter"></i></a></li>
<li><a title="Github" href="https://github.com/apache/netbeans"><i class="fa fa-md fa-github"></i></a></li>
<li><a title="YouTube" href="https://www.youtube.com/user/netbeansvideos"><i class="fa fa-md fa-youtube"></i></a></li>
<li><a title="Atom Feed" href="https://netbeans.apache.org/blogs/atom"><i class="fa fa-mf fa-rss"></i></a></li>
<li><a title="Slack" href="https://tinyurl.com/netbeans-slack-signup/"><i class="fa fa-md fa-slack"></i></a></li>
<li><a title="Issues" href="https://github.com/apache/netbeans/issues"><i class="fa fa-mf fa-bug"></i></a></li>
</ul>
<ul class="menu align-center">
<li><a href="https://github.com/apache/netbeans-antora-tutorials/edit/main/modules/ROOT/pages/tutorials/nbm-povray-2.adoc" title="See this page in github"><i class="fa fa-md fa-edit"></i> See this page in GitHub.</a></li>
</ul>
</section>
</div>
<div class='grid-container incubator-area' style='margin-top: 64px'>
<div class='grid-x grid-padding-x'>
<div class='large-auto cell text-center'>
<a href="https://www.apache.org/">
<img style="height: 60px" title="Apache Software Foundation" src="../../../../_/images/asf_logo_wide.svg" />
</a>
</div>
<div class='large-auto cell text-center'>
<a href="https://www.apache.org/events/current-event.html">
<img style="width:234px; height: 60px;" title="Apache Software Foundation current event" src="https://www.apache.org/events/current-event-234x60.png"/>
</a>
</div>
</div>
</div>
<footer>
<div class="grid-container">
<div class="grid-x grid-padding-x">
<div class="large-auto cell">
<h1><a href="../../../../front/main/about">About</a></h1>
<ul>
<li><a href="../../../../front/main/community/who">Who's Who</a></li>
<li><a href="https://www.apache.org/foundation/thanks.html">Thanks</a></li>
<li><a href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li>
<li><a href="https://www.apache.org/security/">Security</a></li>
</ul>
</div>
<div class="large-auto cell">
<h1><a href="../../../../front/main/community">Community</a></h1>
<ul>
<li><a href="../../../../front/main/community/mailing-lists">Mailing lists</a></li>
<li><a href="../../../../front/main/community/committer">Becoming a committer</a></li>
<li><a href="../../../../front/main/community/events">NetBeans Events</a></li>
<li><a href="https://www.apache.org/events/current-event.html">Apache Events</a></li>
</ul>
</div>
<div class="large-auto cell">
<h1><a href="../../../../front/main/participate">Participate</a></h1>
<ul>
<li><a href="../../../../front/main/participate/submit-pr">Submitting Pull Requests</a></li>
<li><a href="../../../../front/main/participate/report-issue">Reporting Issues</a></li>
<li><a href="../../../../front/main/participate/#documentation">Improving the documentation</a></li>
</ul>
</div>
<div class="large-auto cell">
<h1><a href="../../../../front/main/help">Get Help</a></h1>
<ul>
<li><a href="../../../../front/main/help/#documentation">Documentation</a></li>
<li><a href="../../../../wiki/main/wiki">Wiki</a></li>
<li><a href="../../../../front/main/help/#support">Community Support</a></li>
<li><a href="../../../../front/main/help/commercial-support">Commercial Support</a></li>
</ul>
</div>
<div class="large-auto cell">
<h1><a href="../../../../front/main/download">Download</a></h1>
<ul>
<li><a href="../../../../front/main/download">Releases</a></li>
<li><a href="https://plugins.netbeans.apache.org/">Plugins</a></li>
<li><a href="../../../../front/main/download/#_daily_builds_and_building_from_source">Building from source</a></li>
<li><a href="../../../../front/main/download/#_older_releases">Previous releases</a></li>
</ul>
</div>
</div>
</div>
</footer>
<div class='footer-disclaimer'>
<div class="footer-disclaimer-content">
<p>Copyright &copy; 2017-2025 <a href="https://www.apache.org">The Apache Software Foundation</a>.</p>
<p>Licensed under the Apache <a href="https://www.apache.org/licenses/">license</a>, version 2.0</p>
<div style='max-width: 40em; margin: 0 auto'>
<p>Apache, Apache NetBeans, NetBeans, the Apache feather logo and the Apache NetBeans logo are trademarks of <a href="https://www.apache.org">The Apache Software Foundation</a>.</p>
<p>Oracle and Java are registered trademarks of Oracle and/or its affiliates.</p>
<p>The Apache NetBeans website conforms to the <a href="https://privacy.apache.org/policies/privacy-policy-public.html">Apache Software Foundation Privacy Policy</a></p>
</div>
</div>
</div>
<script src="../../../../_/js/vendor/lunr.js"></script>
<script src="../../../../_/js/search-ui.js" id="search-ui-script" data-site-root-path="../../../.." data-snippet-length="100" data-stylesheet="../../../../_/css/search.css"></script>
<script async src="../../../../search-index.js"></script>
<script src="../../../../_/js/vendor/jquery.min.js"></script>
<script src="../../../../_/js/vendor/what-input.min.js"></script>
<script src="../../../../_/js/vendor/foundation.min.js"></script>
<script src="../../../../_/js/vendor/jquery.colorbox-min.js"></script>
<script src="../../../../_/js/netbeans.js"></script>
<script>
$(function(){ $(document).foundation(); });
</script>
<script src="../../../../_/js/vendor/highlight.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', (event) => {
document.querySelectorAll('pre code').forEach((el) => {
hljs.highlightElement(el);
});
});
</script>
</body>
</html>