-
Posts
2586 -
Joined
-
Last visited
-
Days Won
8
Content Type
Profiles
Forums
Events
Everything posted by RvEYoda
-
Well it is working (low res picture below). Now I need to store all this data as PNGs of different zoom levels - but that I leave for another day.
-
Ok I've updated the data export script a bit. My idea is to send the data via sockets to a png-generating app. This though depends on a lua client class I wrote: EDIT: rewrote it again. This one is actually exporting something :). havent checked everything about it yet but it seems to be working. ----------------- SETTINGS GO HERE ------------- local lowLeft_lon = 35; -- define lower left corner local lowLeft_lat = 41; -- define lower left corner local highRight_lon = 45; -- define upper right corner local highRight_lat = 45; -- define upper right corner local subSquareSide = 37040; -- 20 nautical miles in meters local dimSamples = 1200; -- number of steps per dimension inside each sub section (=pts-1) ------------------ ACTUAL WORK DONE BELOW ----------------- local SUBSECTION = {}; -- for memory reasons, we dont want to reallocate this for each new sub section local lowLeftXZ = LoGeoCoordinatesToLoCoordinates(lowLeft_lon, lowLeft_lat); local highRightXZ = LoGeoCoordinatesToLoCoordinates(highRight_lon, highRight_lat); local xRange = highRightXZ.x - lowLeftXZ.x; local zRange = highRightXZ.z - lowLeftXZ.z; local xStart = lowLeftXZ.x; local zStart = lowLeftXZ.z; local xSteps = math.floor(0.5 + math.abs(xRange) / subSquareSide); local zSteps = math.floor(0.5 + math.abs(zRange) / subSquareSide); local xStep = xRange / xSteps; local zStep = zRange / zSteps; function SaveMap(client) -- Associate a grid index with this client object if (not client.ix) or (not client.iz) then client.ix = 1; client.iz = 1; elseif client.ix > xSteps or client.iz > zSteps then return; end -- Our for-loop local x2 = xStart + client.ix * xStep; local x1 = x2 - xStep; local z2 = zStart + client.iz * zStep; local z1 = z2 - zStep; scanSquare(SUBSECTION, x1, x2, z1, z2, dimSamples, client.ix, client.iz); save(SUBSECTION, client, x1, x2, z1, z2, dimSamples, client.ix, client.iz); --[[ client.ix = client.ix + 1; if client.ix == xSteps then client.ix = 1; client.iz = client.iz + 1; end--]] client.iz = client.iz + 1; if client.iz == zSteps then client.iz = 1; client.ix = client.ix + 1; end end function scanSquare(SUBSECTION, xStart, xEnd, zStart, zEnd, dimSamples, ix, iz) local xStep = (xEnd - xStart) / dimSamples; local zStep = (zEnd - zStart) / dimSamples; SUBSECTION[1] = string.format('%s%s', ix, '\n'); SUBSECTION[2] = string.format('%s%s', iz, '\n'); SUBSECTION[3] = string.format('%s%s', xStart, '\n'); SUBSECTION[4] = string.format('%s%s', xEnd, '\n'); SUBSECTION[5] = string.format('%s%s', zStart, '\n'); SUBSECTION[6] = string.format('%s%s', zEnd, '\n'); local offs = 1 + 6; ptsPerLine = dimSamples + 1; for ix = 0, dimSamples do local x = xStart + ix * xStep; local iBase = offs + ptsPerLine * ix; for iz = 0, dimSamples do local z = zStart + iz * zStep; SUBSECTION[iBase + iz] = string.format('%s%s', LoGetAltitude(x, z), '\n'); end end end function save(SUBSECTION, client, x1, x2, z1, z2, dimSamples) -- Implement saving/compression here local mapData = table.concat(SUBSECTION); local mapDatalen = string.len(mapData); -- Allow blocking client.connection:settimeout(nil); -- Send the header and data client:transmit(string.format('%s%s%s', '!!dnacv02mJ8onvalPD893HNid8V9h6782sdu!!', mapDatalen, '\n')); client:transmit(mapData); -- Resume non-blocking client.connection:settimeout(0.0); end So unsure if you can use this Case.
-
yes but the memory footprint difference is huge, comparing uncompressed to compressed. It all depends on the application what you need. It looks like I might need a decent number of zoom levels for this if I'm going to get it to work properly :P. I aint saying our/your work here is not usable for me. I will definitely use the pictures at a data source regardless. The question is if I should use them to generate the live datasource or if I should use the pictures themselves as a live datasource. The simplest/most direct approach I have in mind right now is cache the files into ram, and uncompress the ones I need on demand. Also Ill need 3-5 zoom levels for my application hmm... Will be a bit of work ^^. I'm thinking something like these steps: 30 m, 100 m, 500 m, 1 km. if we are lucky it shouldnt take more than 50 MB + 5 MB + 0.2 MB + 0.05 MB = 55.25 MB total if I store them compressed. But if I store them uncompressed......well....I simply can't ^^, not enough ram.
-
Then there is also the question....how do we sample values from the images without completely unpacknig them to raw format :P. I have never done such a thing before. I was able to load them in java but that also stored them in a seriously inefficient format. Loading them as OpenGL textures might do better, but I think that also uncompresses them entirely..hm.. Perhaps I have no choice but to load textures/images on demand and unload unused ones. Also to store several different resolution ones for different zoom levels. :/. This is what I didn't really want, but unless I find a way to sample the images without completely loading their raw format into memory, I'm stuck :P. Maybe another way would be to go back to my original idea, basically an adaptive mesh solution.
-
Well, just wrote this right now so 90% it doesnt do the right thing and 75% it wont even run :). But we can build on it. I'd propose something like this: ----------------- SETTINGS GO HERE ------------- local lowLeft_lon = 41; -- define lower left corner local lowLeft_lat = 35; -- define lower left corner local highRight_lon = 45; -- define upper right corner local highRight_lat = 45; -- define upper right corner local subSquareSide = 37040; -- 20 nautical miles in meters local dimSamples = 1200; -- number of steps per dimension inside each sub section (=pts-1) ------------------ ACTUAL WORK DONE BELOW ----------------- function SaveMap() local lowLeftXZ = LoGeoCoordinatesToLoCoordinates(lowLeft_lon, lowLeft_lat); local highRightXZ = LoGeoCoordinatesToLoCoordinates(highRight_lon, highRight_lat); local xRange = highRightXZ.x - lowLeftXZ.x; local zRange = highRightXZ.z - lowLeftXZ.z; local xStart = lowLeftXZ.x; local zStart = lowLeftXZ.z; local xSteps = math.floor(0.5 + math.abs(xRange) / subSquareSide); local zSteps = math.floor(0.5 + math.abs(zRange) / subSquareSide); local xStep = xRange / xSteps; local zStep = zRange / zSteps; local SUBSECTION = {}; -- for memory reasons, we dont want to reallocate this for each new sub section for ix = 1, xSteps do local x2 = xStart + ix * xStep; local x1 = x1 - xStep; for iz = 1,zSteps do local z2 = zStart + iz * zStep; local z1 = z2 - zStep; scanSquare(SUBSECTION, x1, x2, z1, z2, dimSamples); save(SUBSECTION, x1, x2, z1, z2, dimSamples); end end end function scanSquare(SUBSECTION, xStart, xEnd, zStart, zEnd, dimSamples) local xStep = (xEnd - xStart) / dimSamples; local zStep = (zEnd - zStart) / dimSamples; for ix = 0, dimSamples do local x = xStart + ix * xStep; for iz = 0, dimSamples do local z = zStart + iz * zStep; SUBSECTION[1 + ix][1 + iz] = LoGetAltitude(x, z); -- lua indices start with 1 right? end end end function save(SUBSECTION, x1, x2, z1, z2, dimSamples) -- Implement saving/compression here end That would include this box (which I guess we could make larger if we want to)
-
Do you feed the data to some other software for generating the PNGs or do you save to a raw file in between? Maybe your PNG generation is in lua itself?
-
Yeah seems easy enough to do. Will be perfect :D :thumbup: Find bottom left corner, find upper right, split into boxes, save :)
-
Ok. Hmm. I think I might create my own maps anyway, because I want them sampled in an x,z coordinate system, and not lat longs. This is mostly because I do not want to implement new latlong->x,z math every time a new region is introduced. On the downside a saved x,z map means you have to select which one to use, but I find that acceptable. In my lua and in GEAR (if you saw that thread) I no longer have any conversion math but always use lockon's lua's internal variants, and only when I absolutely need to. Java-GEAR never needs to convert (in fact is has no knowledge on how to do so). Well, unless someone has another solution :P. Like, is there a decent way to find these constants: -- =================== -- Constants -- =================== zeroX = 5000000.0; -- Real coordinates beginning zeroZ = 6600000.0; centerX = 11465000.0 - zeroX; -- Circle center centerZ = 6500000.0 - zeroZ; pn40x24_X = 4468608.57 - zeroX; -- point 40dgN : 24dgE pn40x24_Z = 5730893.72 - zeroZ; pn48x24_X = 5357858.31 - zeroX; -- point 48dgN : 24dgE pn48x24_Z = 5828649.53 - zeroZ; pn40x42_X = 4468608.57 - zeroX; -- point 40dgN : 42dgE pn40x42_Z = 7269106.20 - zeroZ; pn48x42_X = 5357858.31 - zeroX; -- ????? 48dgN : 42dgE pn48x42_Z = 7171350.00 - zeroZ; -- distances from the circle center to 48dgN and 40dgN lenNorth = math.sqrt((pn48x24_X-centerX)*(pn48x24_X-centerX) + (pn48x24_Z-centerZ)*(pn48x24_Z-centerZ)); lenSouth = math.sqrt((pn40x24_X-centerX)*(pn40x24_X-centerX) + (pn40x24_Z-centerZ)*(pn40x24_Z-centerZ)); lenN_S = lenSouth - lenNorth; RealAngleMaxLongitude = math.atan((pn40x24_Z - centerZ)/(pn40x24_X - centerX)) * 180.0 /math.pi; -- Map bounds. Degrees! EndWest = 24.0; EndEast = 42.0; EndNorth = 48.0; EndSouth = 40.0; MiddleLongitude = (EndWest + EndEast) / 2; ToLengthN_S = (EndNorth - EndSouth) / lenN_S; ToAngleW_E = (MiddleLongitude - EndWest) / RealAngleMaxLongitude; Can I get these from the game, rather than put them in a file manually? (So that I can make it working in new regions) . UPDATE 2: No i definitely need it in x,z-space. It also improves performance of my programs, since I render in a plane.
-
Thank you! I see you did not make any for Nevada, though that is a minor thing. We can do that later :). Looking forward to what the 1 arcs spacing brings! Can I ask you what programming language you do this in? Do you do everything in lua or use something like C/Java for more "rough work"?
-
Nice. 8bits should also be ok. 255 altitude steps is fine for moving map. PNG also is nice, lossless and all :). Still I will want to consider upping the resolution a bit to perhaps 20-50m spacing between points. How much space will all files take if you use 0.25x0.25 instead of 1x1? 16 times larger? Do you have some sample source code for creating the maps? Or maybe, you have you already created all the pngs needed? :p. If so, am I allowed to use them? :) About 16 bit I created a 16 bit greyscale like this in Java: package imagecompressor; import java.awt.*; import java.awt.image.BufferedImage; import java.awt.image.WritableRaster; import java.io.*; import javax.swing.*; public class Compressor2 extends JPanel { private final Image image; public Compressor2(final BufferedImage image) { this.image = image; } @Override protected void paintComponent(final Graphics g) { g.drawImage(image, 0, 0, g.getClip().getBounds().width, g.getClip().getBounds().height, this); } public static void main(String[] args) throws IOException { // Generate a test image (gradient to make sure we got 16 bit depth and not 8) final int dataW = 1, dataH = 255 * 255; final int[] heightMap = new int[dataW * dataH]; for (int i = 0; i < dataW * dataH; i++) { heightMap[i] = i; } final BufferedImage bi = new BufferedImage(dataW, dataH, BufferedImage.TYPE_USHORT_GRAY); final WritableRaster raster = bi.getRaster(); raster.setPixels(0, 0, dataW, dataH, heightMap); // Render it as a test final Compressor2 test = new Compressor2(bi); final JFrame f = new JFrame(); f.setLayout(new java.awt.GridBagLayout()); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); final GridBagConstraints gbc = new GridBagConstraints(); gbc.fill = java.awt.GridBagConstraints.BOTH; gbc.gridx = 0; gbc.gridy = 0; gbc.weightx = 1; gbc.weighty = 1; f.add(test, gbc); f.setSize(500, 500); f.setLocation(100, 100); f.setVisible(true); } } It seems like my screen is unable to tell the difference between 16 bit or 8 bit greyscale so :P. (don't they just have 8 bits for color components anyway?). So using 16 bit is prob not necessary... Or am I wrong? can normal monitors display above 8 bit greyscale? I guess sometimes you could zoom in on an area which only has let's say 1000-2000 m altitudes, then u could zoom the greyscale as well to make use of your stored 16 bit valules, but that could get confusing. Still I guess it could be used for a manual gain/contrast/brightness control..hmm.
-
I have just one question. Does this take care to use high density in important areas and low density in "flat" areas? - basically what image compression would do. Without this the detail level is probably not so very good. EDIT: Looking at tacview script source code, the answer seems to be NO, see : http://lomac.strasoftware.com/download/misc/DCS/TacviewExportDCS.lua But we can definitely make use of the same principle, we just need a little denser export and add compression/surface fitting on top of it :). I just checked in the game and I think a factor 5 or so in each dimension would be nice to have before applying compression. IF i'm not mistaken, the uncompressed density of the tacview export is: Now we can probably make it 5x more precise by increasing base sample depth and adding intelligent compression/surface fitting. Instead of writing uniformly spaced coordinates directly to a file with lua I send them to a compression tool... Gotta try this
-
Then 16 bpp uncompress seems perfect :). We could do some trial and error to see what kind of compression levels we can apply on top of that to keep the memory usage somewhat low. Right now though, I'm going to sleep. :S
-
Ofc any help or co-coding would be appreciated :). The results of such a project could be open to anyone to use. The first job would be to gather all data required. I am guessing 100x100 images would be alright, and each image could be perhaps 1000x1000 pixels compressed greyscale? We will see how fast the lockon LUA is ^^. I wonder if we can do the compression in lua or if maybe I should send the raw data and compress it outside.
-
Makes sense. If I can't fit all of them reasonably well in memory all at the same time I might make one image grid with lower set of images with less total memory usage for more zoomed out. My initial idea is to not render a fixed number of pixels, but rather sample a fixed number of pixels, and render an interpolation between them, though this might be what you meant.
-
Sry I didnt read your post properly before. Using picture compression, nice! It would be the same way as saving adaptive key points . That might be a very good idea. Save image files and use jpeg/other compression on them to emulate the parametric surfaces...That's not bad :). Thanks for the idea... This is perhaps what I need. 1. Split the region into 100x100 pictures. 2. Save each picture with a certain lossy compression level. (some will be super small in storage size, others large, but they will all be the same amount of renderable pixels...) ...hmm This is good. Low cpu usage when running and easy implementation both generating the files and loading data from them.
-
What I want to, more precise, is to have a function like getAltitude(x,z), which gives the same answer as the built in lockon lua function, but doesn't require lockon :). (and it must work in the projected coordinate system of lockon). This would allow me to create certain cool moving map features. Preferably I would want a full map setup that maps well to the lockon coordinate projection, but just altitudes are a start (again; we can't use open databases directly since they use a properly curved surface while lockon uses a flat projection, so grabbing altitude data directly from lockon will produce much more accurate results!) . The precise storage model I havent decided on, which is what I want to find a good solution for. So far my best idea is a set of variably sized parametric surfaces, dividing the sim regions into smaller sub regions. A uniform grid is far too imprecise and requires too much memory. Linearly interpolating from a set of altitudes at key positions is actually the same (by definition :P) as the first order parametric surfaces (planes). Though I prefer if we could make it a higher order. If I start working on it I will probably experiment with it in matlab :P. Could be cool! Basically something like function getAltitude(x,z) SubSection surface = getSubSection(x,y) // Find the sub section (= parametric surface) belonging to this coordinate return surface.getAltitude(x,z) // Calculate the altitude at x,z on the parametric surface that is this sub section end For a later time that could be interesting, since it is a simple thing to do with a getAltitude function, though I have nothing that requires such a thing at the moment.
-
The question then becomes what kind of database representation would you use, after you first have found a 1:1 mapping to Fc's/DCS's flat world projection. (if you use the getAltitude method you dont have to use the mapping, just decide on storage math) For example a poor implementation would be interpolated altitudes from 1 km uniform points - nowhere near good enough. Much better would be to use some kind of parametric surface representations of different areas with a somewhat low number of control points. You could also store curves with constant altitude. (easy to draw) What I'm looking for are suggestions on how to solve these mathematical problems. EDIT: I have an idea... which also works good for the getAltitude method. It works by storing N parametric surfaces of variable size, where each surface has certain limitations (a certain optimization for control point density). The generation process goes something like this: You start in one corner of the world map 1. Decide on the smallest level of sub section for a parametric surface. Point scan this sub section with getAltitude and create the required control points which maps best to the point scan. Save sub section. 2. Do (1) on all neighbors. If compatible (optimizations say OK), merge sections, otherwise, keep separated. 3. Do this all over the map, you get a non-uniform grid of parametric surfaces of different shapes and sizes. This should be close to optimal? :P Ok so then I have stored it. I can then ask what altitudes are where.....Then comes the real question. How to draw from this ^^. Cause all these steps do 1-2-3, are to create my own getAltitude function. :S. I must also find a way to draw from it. Hmm that might be easier than expected. Maybe it is enough just to define a drawing density, for example 100x100 pixels, call the function 100x100 times each time the map camera changes and draw interpolated values in between.....nice.....that could work :P
-
I am working on this project here : http://forums.eagle.ru/showthread.php?t=76804 (It is a lot more finished than that thread suggests ^^), and I want to put some cool features into it. Also it will have a AWACS/GCI/commander's view with the ability to see all datalinked aircraft and their radar returns - and also the ability to share mark points and similar. Pilots, leads, commanders can send and share mission and target point data and messages in real time. Adding a moving map capability to this would be nice, or at least some altitude curves.
-
I think you misunderstood my post. I have no intention of putting anything new into the game. My question is how to map the current mathematical representation that the game has of lat-long-altitudes to a map display on an external monitor/moving map. Because the current implementation is a flat world, you can't just use already existing databases - They will miss, and I require at least that you will see someone flying in a canyon in both the game and the external monitor ;)
-
This question goes out to both ED developers but also all forum members. All help is appreciated :). I am thinking of ways to generate an accurate altitude map/moving map for external awacs/instrument/dlink purposes primarily, both fc and dcs. I know that FC/DCS uses a flat world projection of the selected theater and this does not perfectly match for example google earth/similar things all that well: the further you get from the sim map "center"(align point?) the more wrong the map would be. For example tacview, has a very nice looking map with altitude but it quite often looks like you fly through a mountain if you are not close to the map center. That being said, I am not going to give up that easily. I am considering a few ways we migth be able to generate an accurate map. 1. Perform some mathematical modifications to the open databases to get them accurate enough with the sim. We must also consider that other regions than black sea/nevada could be used in the future, and not fix ourselves completely to a center at a specific lat/lon. 2. If ED would allow us to use what is stored in the sim currently (though this is probably not possible due to IP reasons, still it probably wont hurt to ask). Maybe there is something here? "Eagle Dynamics\DCS A-10C\Bazar\Map". We would need to learn the format though. 3. Generate our own database. This wont be easy, but NOT impossible. In the config/export.lua there is a function LoGetAltitude(x, z) -- (args - 2 : meters, results - 1 : altitude above terrain surface, meters) which In principle could let us build our own database. I am not sure what kind of data storage/representation is the best to use here for our database, but I would guess that we would not want to use sime kind of altitude table, but rather some form of curve representation, and highly adaptive. Building such a database could be quite...challanging :). Maybe there is someone here with experience in such a subject.
-
The future of LEAVU, a more general tool?
RvEYoda replied to RvEYoda's topic in Lock On: Flaming Cliffs 1 & 2
Ok for everyone that wants to inspect and/or contribute to the source, "Public" SVN account is up! (read-only) It includes everything you need, from fc2 exports to native jogl libs and java code. I recommend you use Netbeans IDE for both checking it out and trying it. 1. Install 32bit Java JDK with Neatbeans 2. Open Netbeans and checkout the SVN repository from: rep: https://www.gigurra.se/svn/GEAR/GEAR user: public password (blank): -
The future of LEAVU, a more general tool?
RvEYoda replied to RvEYoda's topic in Lock On: Flaming Cliffs 1 & 2
Just had a look at JAXB, which I actually havent used :), but maybe should have. Ideally I would want to generate the xml format from a java class, and skip the schema, or go from java class -> xml schema -> xml (and be able to map both ways). BUT myself I actually didn't think/know about schemas etc, so I went and did the presets xml manually. but... we could always change it? :). However as you note in the xml presets there is a custom section called "specifics" where an instrument can put any text string they want, so that might be tricky to define in a schema? or maybe not :P. Here is how I do it right now (blunt brute force^^) : package gear.xml; import gear.GEAR; import gear.dlink.DlinkHubGui; import gear.instrument.Instrument; import gear.instrument.manager.InstrumentManager; import gear.instrument.manager.WindowSettings; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JOptionPane; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; public final class PresetLoader { private final GEAR gear; private final InstrumentManager im; public PresetLoader(final GEAR gear, final InstrumentManager im) { this.gear = gear; this.im = im; } public final void loadPreset(final File file) { try { final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(file); doc.getDocumentElement().normalize(); final Element root = doc.getDocumentElement(); // do Main gui final Element mgs = (Element) root.getElementsByTagName("mainguisettings").item(0); final String wsexnofocusStr = mgs.getElementsByTagName("nofocusjni").item(0).getTextContent(), volumeStr = mgs.getElementsByTagName("volume").item(0).getTextContent(); // do sim client final Element simClient = (Element) mgs.getElementsByTagName("simclient").item(0); final String simClienthostStr = simClient.getElementsByTagName("host").item(0).getTextContent(), simClientportStr = simClient.getElementsByTagName("port").item(0).getTextContent(), simClientautoconnectStr = simClient.getElementsByTagName("autoconnect").item(0).getTextContent(); // do dlink client final Element dlinkClient = (Element) mgs.getElementsByTagName("dlinkclient").item(0); final String dlinkClienthostStr = dlinkClient.getElementsByTagName("host").item(0).getTextContent(), dlinkClientportStr = dlinkClient.getElementsByTagName("port").item(0).getTextContent(), dlinkClientnameStr = dlinkClient.getElementsByTagName("name").item(0).getTextContent(), dlinkClientpasswdStr = dlinkClient.getElementsByTagName("password").item(0).getTextContent(), dlinkClientautoconnectStr = dlinkClient.getElementsByTagName("autoconnect").item(0).getTextContent(); // Remove all previous instruments and disconnect clients before continuing gear.disconnectAll(); //im.killAllInstruments(); // load main gui settings gear.setWSEXNOACTIVATE(Boolean.valueOf(wsexnofocusStr)); gear.setVolume(Integer.valueOf(volumeStr)); // load simclient settings gear.setSimHost(simClienthostStr); gear.setSimPort(Integer.valueOf(simClientportStr)); if (Boolean.valueOf(simClientautoconnectStr)) { gear.onConnectSimButton(); } // load dlinkclient settings gear.setDlinkHost(dlinkClienthostStr); gear.setDlinkPort(Integer.valueOf(dlinkClientportStr)); gear.setDlinkId(dlinkClientnameStr); gear.setDlinkPassword(dlinkClientpasswdStr); if (Boolean.valueOf(dlinkClientautoconnectStr)) { gear.onConnectDlinkButton(); } gear.updateMainguiTextfields(); // do dlink host final NodeList dlinkHostList = mgs.getElementsByTagName("dlinkhost"); for (int i = 0; i < dlinkHostList.getLength(); i++) { final Element dlinkHost = (Element) dlinkHostList.item(i); final String dlinkHostportStr = dlinkHost.getElementsByTagName("port").item(0).getTextContent(), dlinkHostpasswdStr = dlinkHost.getElementsByTagName("password").item(0).getTextContent(), dlinkHostautoconnectStr = dlinkHost.getElementsByTagName("autoconnect").item(0).getTextContent(); // load server if (Boolean.valueOf(dlinkHostautoconnectStr)) { new DlinkHubGui(gear.getMainGuiPos(), Integer.valueOf(dlinkHostportStr), dlinkHostpasswdStr).setVisible(true); } } { // do instruments final Element instrBaseElem = (Element) root.getElementsByTagName("instruments").item(0); final NodeList instrumentNodes = instrBaseElem.getElementsByTagName("instrument"); for (int i = 0; i < instrumentNodes.getLength(); i++) { final Element base = (Element) instrumentNodes.item(i); final String nameStr = base.getElementsByTagName("name").item(0).getTextContent(), sizexStr = base.getElementsByTagName("sizex").item(0).getTextContent(), sizeyStr = base.getElementsByTagName("sizey").item(0).getTextContent(), posxStr = base.getElementsByTagName("posx").item(0).getTextContent(), posyStr = base.getElementsByTagName("posy").item(0).getTextContent(), wndFrameStr = base.getElementsByTagName("windowframe").item(0).getTextContent(); final Element instrSpecifics = (Element) base.getElementsByTagName("specifics").item(0); im.onRequestCreateNewInstrument(nameStr, new WindowSettings(Integer.valueOf(sizexStr), Integer.valueOf(sizeyStr), Integer.valueOf(posxStr), Integer.valueOf(posyStr), Boolean.valueOf(wndFrameStr)), instrSpecifics); } } } catch (Exception ex) { Logger.getLogger(PresetLoader.class.getName()).log(Level.SEVERE, null, ex); JOptionPane.showMessageDialog(null, "Failed to load preset from file: " + file.getName()); } } public final void savePreset(final File selectedFile) { if (!selectedFile.exists()) { try { selectedFile.createNewFile(); } catch (Exception e) { JOptionPane.showMessageDialog(null, e.getMessage()); return; } } if (!selectedFile.canWrite()) { JOptionPane.showMessageDialog(null, "Unable to open file " + selectedFile.getName() + " for writing"); return; } try { final BufferedWriter bw = new BufferedWriter(new FileWriter(selectedFile, false)); bw.write(createXmlPreset()); bw.close(); } catch (IOException ex) { Logger.getLogger(PresetLoader.class.getName()).log(Level.SEVERE, null, ex); } } private final String createXmlPreset() { final XmlBuilder xb = new XmlBuilder(); xb.addSection("root"); { xb.addSection("mainguisettings"); { xb.addEntry("nofocusjni", gear.getWSEXNOACTIVATE()); xb.addEntry("volume", gear.getVolume()); xb.addSection("simclient"); { xb.addEntry("host", gear.getSimHost()); xb.addEntry("port", gear.getSimPort()); xb.addEntry("autoconnect", gear.getSimClientAlive()); } xb.closeSection(); // close simclient xb.addSection("dlinkclient"); { xb.addEntry("host", gear.getDlinkHost()); xb.addEntry("port", gear.getDlinkPort()); xb.addEntry("name", gear.getDlinkId()); xb.addEntry("password", gear.getDlinkPassword()); xb.addEntry("autoconnect", gear.getDlinkClientAlive()); } xb.closeSection(); // close dlinkclient xb.addSection("instruments"); { for (final Instrument i : im.getActiveInstruments()) { xb.addSection("instrument"); xb.addString(i.getXml()); xb.closeSection(); } } xb.closeSection(); // close instruments } xb.closeSection(); // close mainguisettings } xb.closeSection(); // close root return xb.toString(); } } Update: I found out now there is a JDK tool called "schemagen" which simply creates an xml schema from a java class. However it doesn't seem like there is any built in netbeans support for this, so it needs to be run from the command line..hmm.. Maybe I should just make my own using java reflection at some point ;P Moa we must find a better way to communicate. This two-posts-per-day is tooo slow. What we've told each other in a week can be done in 20 minutes on any IM program. It doesn't matter if it's skype or msn or icq. Something similar is required where we dont have to connect to a specific service for our communication (an irc channel or kenai chat is not good enough, we have to connect to it manually, both, beforehand, if we did that with all our contacts at least I'd have a million windows open at all times). I believe GEAR would be 2x as competent if you joined in. -
The future of LEAVU, a more general tool?
RvEYoda replied to RvEYoda's topic in Lock On: Flaming Cliffs 1 & 2
Moa u speak my language :D. Sending commands to lockon lua from gear is already on the drawing board and 90% already implemented. Moving map both inside gear and outside would be fantastic too, but how do you propose we handle the coordinates? Lockon has a flat world, x-plane has a round etc, we cant just use lat longs and the same map. In GEAR I actually don't expose a coordinate system at all. I instead use a replaceable data interface (just an abstract base class which u implement specific for your sim) that produces snapshots of Altitude msl, range, bearing, aspect. However instruments can ask for the interface to produce an implementation specific coordinate from a bearing/range/altitude/aspect and also the other way around, but all you get is an "Object" which u really dont know much about (Except it is useful for example for mark points and datalink messages so you can save certain points on the map, a BRALTASP snapshot is only valid if you stay in that point where you made it where as an implementation specific point is valid forever, cause it probably saves as lat/long/alt) It goes like this Lockon <-> lua <-> gear's fc2 data parser <-> gear's fc2togear data interface <-> gear instruments. The Data instruments in gear are completely independent of any fc2 stuff and this is something I want to keep it like, so if we want a moving map that might require knowledge of the underlying coordinate system, then we should need to implement some new abilities in the data interface. If you are on Msn I can show you arrg, but you might be working daytime also :helpsmilie: Here is the base class I'm using for the data interface, so you get an idea of what I mean: package gear.instrument.datainterface; import gear.GEAR; import java.io.Serializable; import java.util.UUID; import net.Parser; public abstract class DataInterface { private final GEAR gear; public abstract void inputDlinkData(final Object data); public abstract void inputSimData(final Object data); public abstract Parser getSimDataParser(); public abstract Serializable[] genDataForDlinkUpload(final UUID myUuid, final String myDlinkId); public SnapshotRdrCursor getSnapshotRdrCursor() { return new SnapshotRdrCursor(0, 0, 0, false, false); } public SnapshotA2ATarget[] getSnapshotTargets() { return new SnapshotA2ATarget[0]; } public SnapshotA2ADatalinkedWingman[] getSnapshotA2ADatalinkedWingmen() { return new SnapshotA2ADatalinkedWingman[0]; } public SnapshotNavPoint[] getSnapshotNavPoints() { return new SnapshotNavPoint[0]; } public SnapshotOwnPosition getSnapshotOwnPosition() { return new SnapshotOwnPosition(0, 0, false); } public SnapshotRadarConfig getSnapshotRadarConfig() { return new SnapshotRadarConfig(0, 0, 0, 0, 0, 0, 0, false, "", false); } public Serializable braltSnapshotToImplSpecCoords(final float altMsl_m, final float offNoseBearing_deg, final float fromAcRange_m) { return null; } public SnapshotPosition implSpecCoordsToBraltSnapshot(final Serializable backingData) { return null; } public DataInterface(final GEAR gear) { this.gear = gear; } public final UUID getMyUuid() { return gear.myUuid; } public final String getMyDlinkid() { return gear.getDlinkId(); } public void sendDlinkMsg(final Serializable... ss) { gear.transmitOverDlink(ss); } } The implemention for fc2 in gear looks something like this : package fc2; import fc2.nav.Fc2AircraftPosition; import fc2.nav.Fc2Position; import fc2.nav.Fc2WingMan; import fc2.state.Fc2DataContainer; import fc2.state.Fc2AcModes; import fc2.state.Fc2ContactMemory; import fc2.state.Fc2DlinkMemory; import fc2.state.Fc2Navpoints; import fc2.state.Fc2Payload; import fc2.state.Fc2RadarSettings; import fc2.state.Fc2SelfData; import fc2.state.Fc2TEWS; import gear.GEAR; import gear.instrument.datainterface.DataInterface; import gear.instrument.datainterface.SnapshotNavPoint; import gear.instrument.datainterface.SnapshotA2ADatalinkedWingman; import gear.instrument.datainterface.SnapshotOwnPosition; import gear.instrument.datainterface.SnapshotA2ATarget; import gear.instrument.datainterface.SnapshotRdrCursor; import gear.instrument.datainterface.SnapshotPosition; import gear.instrument.datainterface.SnapshotRadarConfig; import gear.instrument.globals.GlobalDlinkMessage; import gear.instrument.globals.Globals; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.UUID; import net.Parser; import net.PatternFinder; import static fc2.Fc2Utils.*; public final class Fc2DataManager extends DataInterface { // Dcs/fc format private final Fc2AcModes acModes; private final Fc2ContactMemory contactMemory; private final Fc2Navpoints navpoints; private final Fc2Payload payload; private final Fc2RadarSettings radarSettings; private final Fc2SelfData selfData; private final Fc2TEWS tews; private final Fc2DlinkMemory dlinkMemory; private final HashMap<String, Fc2DataContainer> simDataContainers = new HashMap<String, Fc2DataContainer>(10); // Gear format private SnapshotNavPoint[] snapshotNavPoints = new SnapshotNavPoint[0]; private SnapshotA2ATarget[] snapshotTargets = new SnapshotA2ATarget[0]; private SnapshotOwnPosition snapshotOwnPosition = new SnapshotOwnPosition(0, 0, false); private SnapshotRdrCursor snapshotHsdCursor = new SnapshotRdrCursor(0, 0, 0, true, false); private SnapshotA2ADatalinkedWingman[] snapshotDatalinkedWingmen = new SnapshotA2ADatalinkedWingman[0]; private SnapshotRadarConfig snapshotRadarConfig = new SnapshotRadarConfig(0, 0, 0, 0, 0, 0, 0, false, "LV", false); private boolean simSnapshotsUpToDate = false, dlinkSnapshotsUpToDate = false; @Override public final SnapshotOwnPosition getSnapshotOwnPosition() { ensureSnapshotsUpToDate(); return snapshotOwnPosition; } @Override public final SnapshotNavPoint[] getSnapshotNavPoints() { ensureSnapshotsUpToDate(); return snapshotNavPoints; } @Override public final SnapshotA2ATarget[] getSnapshotTargets() { ensureSnapshotsUpToDate(); return snapshotTargets; } @Override public final SnapshotA2ADatalinkedWingman[] getSnapshotA2ADatalinkedWingmen() { ensureSnapshotsUpToDate(); return snapshotDatalinkedWingmen; } @Override public final SnapshotRdrCursor getSnapshotRdrCursor() { ensureSnapshotsUpToDate(); return snapshotHsdCursor; } @Override public final SnapshotRadarConfig getSnapshotRadarConfig() { ensureSnapshotsUpToDate(); return snapshotRadarConfig; } @Override public Serializable braltSnapshotToImplSpecCoords(final float altMsl_m, final float offNoseBearing_deg, final float fromAcRange_m) { return snapshotToImplPos(selfData.getMyPos(), altMsl_m, offNoseBearing_deg, fromAcRange_m); } @Override public SnapshotPosition implSpecCoordsToBraltSnapshot(final Serializable backingData) { return (backingData instanceof Fc2Position) ? implPosToSnapshot(selfData.getMyPos(), (Fc2Position) backingData) : null; } @Override public final void inputSimData(final Object simData) { if (simData instanceof byte[]) { final String data = new String((byte[]) simData); final ArrayList<String> lines = new ArrayList<String>(data.length() / 7); int stringStart = 0; for (int i = 0; i < data.length(); i++) { if (data.charAt(i) == '\n' || i + 1 == data.length()) { lines.add(data.substring(stringStart, i)); stringStart = i + 1; } } int lineIndex = 0; boolean noUpdate = simSnapshotsUpToDate; while (lineIndex < lines.size()) { final Fc2DataContainer receiver = simDataContainers.get(lines.get(lineIndex)); if (receiver != null) { lineIndex = receiver.insertData(lines, lineIndex); noUpdate = false; } else { lineIndex++; } } simSnapshotsUpToDate = noUpdate; } } @Override public final Parser getSimDataParser() { return new Parser(new PatternFinder("!!dnacv02mJ8onvalPD893HNid8V9h6782sdu!!".getBytes())); } @Override public final void inputDlinkData(final Object data) { if (data instanceof Fc2WingMan) { dlinkMemory.insertWingman((Fc2WingMan) data); dlinkSnapshotsUpToDate = false; } else if (data instanceof GlobalDlinkMessage) { Globals.insertGlobalDlinkMessage((GlobalDlinkMessage) data); } } @Override public final Serializable[] genDataForDlinkUpload(final UUID myUuid, final String myDlinkId) { final Fc2AircraftPosition ap = selfData.getMyPos(); return new Serializable[]{new Fc2WingMan( myUuid, ap.typeCsv, ap.x_m, ap.z_m, ap.altMsl_m, ap.heading_rads, ap.worldID, ap.coalitionID, myDlinkId, contactMemory.getContacts(5))}; } private final void ensureSnapshotsUpToDate() { if (!simSnapshotsUpToDate) { snapshotNavPoints = implNavpointsToSnapshots(selfData, navpoints); snapshotOwnPosition = implOwnPosToSnapshot(selfData); snapshotTargets = implTargetsToSnapshots(selfData, contactMemory); snapshotHsdCursor = implRadCursorToSnapshot(selfData, radarSettings); snapshotRadarConfig = implRadarConfToSnapshot(radarSettings); simSnapshotsUpToDate = true; } if (!dlinkSnapshotsUpToDate) { snapshotDatalinkedWingmen = implDlinkedWingmenToSnapshots(selfData, dlinkMemory); dlinkSnapshotsUpToDate = true; } } @SuppressWarnings("CallToThreadStartDuringObjectConstruction") public Fc2DataManager(final GEAR gear) { super(gear); addImplSimDataContainer(simDataContainers, this.acModes = new Fc2AcModes()); addImplSimDataContainer(simDataContainers, this.contactMemory = new Fc2ContactMemory()); addImplSimDataContainer(simDataContainers, this.navpoints = new Fc2Navpoints()); addImplSimDataContainer(simDataContainers, this.payload = new Fc2Payload()); addImplSimDataContainer(simDataContainers, this.selfData = new Fc2SelfData()); addImplSimDataContainer(simDataContainers, this.radarSettings = new Fc2RadarSettings(this.selfData)); addImplSimDataContainer(simDataContainers, this.tews = new Fc2TEWS(gear.audioBank)); this.dlinkMemory = new Fc2DlinkMemory(); this.tews.start(); this.dlinkMemory.start(); } } It uses a few utility classes for coordinate manipulation. -
The future of LEAVU, a more general tool?
RvEYoda replied to RvEYoda's topic in Lock On: Flaming Cliffs 1 & 2
Well I think the current system is as fast as it gets. BUT if you can make a faster one then we will definitely want to use that :). I made some tests with text by rendering preloaded geometry (display lists and/or VBOs generated from AWT font coordinates) vs JOGLs preloaded texture based textrenderer, and...the textrenderer wins with a speed factor 2x-3x. To me that is quite convincing, and it also has nice AA etc...so I guess its performance is acceptable. The main point is, the text probably in all reason should be the heaviest part of my application. Rendering low poly sets of lines is simply much lighter than curved text or painting textures, at least that is my conclusion. Again I'm interested in seeing your results! About your web service, will you read/write to gear or to the lua exports? I have been thinking of getting data from xml instead of strings from the lua, but havent put my mind to that yet. Doing IO to gear via a web service I guess could also be fun :P. If you want to write such an interface then it would be great to incorporate it into the main project. I am already using simple xml for my gear presets: <?xml version="1.0" encoding="UTF-8"?> <root> <mainguisettings> <nofocusjni>true</nofocusjni> <volume>100</volume> <simclient> <host>localhost</host> <port>8079</port> <autoconnect>true</autoconnect> </simclient> <dlinkclient> <host>www.gigurra.se</host> <port>11009</port> <name>User</name> <password>red</password> <autoconnect>true</autoconnect> </dlinkclient> <!-- <dlinkhost> <port>11009</port> <password>red</password> <autoconnect>true</autoconnect> </dlinkhost> <dlinkhost> <port>11011</port> <password>blue</password> <autoconnect>true</autoconnect> </dlinkhost>--> </mainguisettings> <instruments> <instrument> <name>Mfd20</name> <sizex>400</sizex> <sizey>400</sizey> <posx>250</posx> <posy>200</posy> <windowframe>true</windowframe> <specifics> <bezelbuttons>true</bezelbuttons> <qp1>1</qp1> <qp2>2</qp2> <qp3>3</qp3> <curqp>1</curqp> <kbbindings> <key> <base>NUMBER1</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>NUMBER2</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>NUMBER3</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>NUMBER4</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>NUMBER5</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>NUMBER6</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>NUMBER7</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>NUMBER8</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>NUMBER9</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>NUMBER0</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>F1</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>F2</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>F3</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>F4</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>F5</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>F6</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>F7</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>F8</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>F9</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> <key> <base>F10</base> <modifier>LCTRL</modifier> <modifier>LSHFT</modifier> </key> </kbbindings> </specifics> </instrument> <instrument> <name>Mfd20</name> <sizex>400</sizex> <sizey>400</sizey> <posx>650</posx> <posy>200</posy> <windowframe>true</windowframe> <specifics> <bezelbuttons>false</bezelbuttons> <qp1>2</qp1> <qp2>4</qp2> <qp3>5</qp3> <curqp>0</curqp> <kbbindings> <key> <base>NUMBER1</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>NUMBER2</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>NUMBER3</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>NUMBER4</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>NUMBER5</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>NUMBER6</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>NUMBER7</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>NUMBER8</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>NUMBER9</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>NUMBER0</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>F1</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>F2</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>F3</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>F4</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>F5</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>F6</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>F7</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>F8</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>F9</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> <key> <base>F10</base> <modifier>RCTRL</modifier> <modifier>RSHFT</modifier> </key> </kbbindings> </specifics> </instrument> </instruments> </root> Considering putting java7 code into gear. I basically emulated the event based IO stuff which is using OS native stuff in java 7, by using standard Java 6 threads, but it's so much prettier in java7... example below: public static void main(String[] args) throws IOException { final AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open(); server.bind(new InetSocketAddress(12345)).accept(server, new CH()); } private static class CH implements CompletionHandler<AsynchronousSocketChannel, AsynchronousServerSocketChannel> { @Override public void completed(AsynchronousSocketChannel result, AsynchronousServerSocketChannel server) { System.err.println("NEW CLIENT, get next!"); server.accept(server, this); } @Override public void failed(Throwable exc, AsynchronousServerSocketChannel server) { try { System.err.println("Server bailing!"); server.close(); } catch (IOException ex) { Logger.getLogger(JavaAsync.class.getName()).log(Level.SEVERE, null, ex); } } } -
The future of LEAVU, a more general tool?
RvEYoda replied to RvEYoda's topic in Lock On: Flaming Cliffs 1 & 2
Approaching a point where gear has virtually all features of LEAVU(2). When I get home this weekend I'll try to get my eyes away from MLG Anaheim (Starcraft II) and take a first step towards release. The first thing I'll do is to create a public account to access the svn repository I'm using for GEAR. EDIT: Just realized that JRE/JDK/Java 7 was just released. Tested and works perfectly with gear. Too bad we can't use its new features, as most users probably will only have java6. Parts of java7 seem really useful like asyncronous io and switch/case on strings. Performance wise it seems to be 1:1 with java6. Also the new generics look interesting.