diff options
author | Sven Gothel <[email protected]> | 2019-12-31 18:23:02 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2019-12-31 18:23:02 +0100 |
commit | 332dd8550a2301427dd942d2a77cb59ebd3ec92e (patch) | |
tree | 0c860a40c05ba5b27d99770a433b922cbf685f70 /src/net/java/joglutils/model/examples/DisplayListRenderer.java | |
parent | 7ea189170b6ae75b7e15be43344a785eb56bb48a (diff) |
Diffstat (limited to 'src/net/java/joglutils/model/examples/DisplayListRenderer.java')
-rw-r--r-- | src/net/java/joglutils/model/examples/DisplayListRenderer.java | 351 |
1 files changed, 180 insertions, 171 deletions
diff --git a/src/net/java/joglutils/model/examples/DisplayListRenderer.java b/src/net/java/joglutils/model/examples/DisplayListRenderer.java index 4989356..4f3c63f 100644 --- a/src/net/java/joglutils/model/examples/DisplayListRenderer.java +++ b/src/net/java/joglutils/model/examples/DisplayListRenderer.java @@ -9,164 +9,173 @@ package net.java.joglutils.model.examples;
-import net.java.joglutils.model.*;
-import com.sun.opengl.util.texture.*;
-import com.sun.opengl.util.texture.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
+
import javax.imageio.ImageIO;
-import javax.media.opengl.*;
+
+import com.jogamp.opengl.GL;
+import com.jogamp.opengl.GL2;
+import com.jogamp.opengl.GL2GL3;
+import com.jogamp.opengl.GLAutoDrawable;
+import com.jogamp.opengl.GLProfile;
+import com.jogamp.opengl.fixedfunc.GLLightingFunc;
+import com.jogamp.opengl.fixedfunc.GLMatrixFunc;
+import com.jogamp.opengl.util.texture.Texture;
+import com.jogamp.opengl.util.texture.TextureCoords;
+import com.jogamp.opengl.util.texture.awt.AWTTextureIO;
+
import net.java.joglutils.model.ResourceRetriever;
+import net.java.joglutils.model.iModel3DRenderer;
import net.java.joglutils.model.geometry.Bounds;
import net.java.joglutils.model.geometry.Material;
import net.java.joglutils.model.geometry.Mesh;
import net.java.joglutils.model.geometry.Model;
import net.java.joglutils.model.geometry.Vec4;
-import net.java.joglutils.model.iModel3DRenderer;
/**
*
* @author RodgersGB
- *
+ *
* modifications made by Brian Wood and Z-Knight
*/
public class DisplayListRenderer implements iModel3DRenderer {
private static DisplayListRenderer instance = new DisplayListRenderer();
- private DisplayListCache listCache = new DisplayListCache();
+ private final DisplayListCache listCache = new DisplayListCache();
private HashMap<Integer, Texture> texture;
private int modelBoundsList = -1;
private int objectBoundsList = 1;
private boolean isDebugging = true;
-
+
/** Creates a new instance of DisplayListModel3D */
public DisplayListRenderer() {
}
-
+
public static DisplayListRenderer getInstance() {
return instance;
}
- public void debug(boolean value) {
+ public void debug(final boolean value) {
this.isDebugging = value;
}
-
- public void render(Object context, Model model)
+
+ public void render(final Object context, final Model model)
{
GL2 gl = null;
-
+
if (context instanceof GL2)
gl = (GL2) context;
-
+
else if (context instanceof GLAutoDrawable)
gl = ((GLAutoDrawable) context).getGL().getGL2();
-
+
if (gl == null) {
return;
}
-
+
if (model == null) {
return;
}
-
+
int displayList = listCache.get(model);
-
+
if(displayList < 0) {
displayList = initialize(gl, model);
if (this.isDebugging)
System.out.println("Initialized the display list for model: " + model.getSource());
}
-
+
// save some current state variables
- boolean isTextureEnabled = gl.glIsEnabled(GL2.GL_TEXTURE_2D);
- boolean isLightingEnabled = gl.glIsEnabled(GL2.GL_LIGHTING);
- boolean isMaterialEnabled = gl.glIsEnabled(GL2.GL_COLOR_MATERIAL);
-
+ final boolean isTextureEnabled = gl.glIsEnabled(GL.GL_TEXTURE_2D);
+ final boolean isLightingEnabled = gl.glIsEnabled(GLLightingFunc.GL_LIGHTING);
+ final boolean isMaterialEnabled = gl.glIsEnabled(GLLightingFunc.GL_COLOR_MATERIAL);
+
// check lighting
- if (!model.isUsingLighting()) { gl.glDisable(GL2.GL_LIGHTING); }
-
+ if (!model.isUsingLighting()) { gl.glDisable(GLLightingFunc.GL_LIGHTING); }
+
// check texture
- if (model.isUsingTexture()) { gl.glEnable(GL2.GL_TEXTURE_2D); }
- else { gl.glDisable(GL2.GL_TEXTURE_2D); }
-
+ if (model.isUsingTexture()) { gl.glEnable(GL.GL_TEXTURE_2D); }
+ else { gl.glDisable(GL.GL_TEXTURE_2D); }
+
// check wireframe
- if (model.isRenderingAsWireframe()) { gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_LINE); }
- else { gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_FILL); }
-
- gl.glDisable(GL2.GL_COLOR_MATERIAL);
-
+ if (model.isRenderingAsWireframe()) { gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_LINE); }
+ else { gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_FILL); }
+
+ gl.glDisable(GLLightingFunc.GL_COLOR_MATERIAL);
+
gl.glPushMatrix();
-
+
// check for unit size model
if (model.isUnitizeSize()) {
- float scale = 1.0f/model.getBounds().getRadius();
+ final float scale = 1.0f/model.getBounds().getRadius();
gl.glScalef(scale, scale, scale);
}
-
+
if (model.isCentered()) {
- Vec4 center = model.getCenterPoint();
+ final Vec4 center = model.getCenterPoint();
gl.glTranslatef(-center.x, -center.y, -center.z);
}
-
+
if (model.isRenderModel())
gl.glCallList(displayList);
-
+
// Disabled lighting for drawing the boundary lines so they are all white (or whatever I chose)
- gl.glDisable(GL2.GL_LIGHTING);
+ gl.glDisable(GLLightingFunc.GL_LIGHTING);
if (model.isRenderModelBounds())
gl.glCallList(modelBoundsList);
if (model.isRenderObjectBounds())
gl.glCallList(objectBoundsList);
-
+
gl.glPopMatrix();
// Reset the flags back for lighting and texture
if (isTextureEnabled) {
- gl.glEnable(GL2.GL_TEXTURE_2D);
+ gl.glEnable(GL.GL_TEXTURE_2D);
} else {
- gl.glDisable(GL2.GL_TEXTURE_2D);
+ gl.glDisable(GL.GL_TEXTURE_2D);
}
if (isLightingEnabled) {
- gl.glEnable(GL2.GL_LIGHTING);
+ gl.glEnable(GLLightingFunc.GL_LIGHTING);
} else {
- gl.glDisable(GL2.GL_LIGHTING);
+ gl.glDisable(GLLightingFunc.GL_LIGHTING);
}
if (isMaterialEnabled) {
- gl.glEnable(GL2.GL_COLOR_MATERIAL);
+ gl.glEnable(GLLightingFunc.GL_COLOR_MATERIAL);
} else {
- gl.glDisable(GL2.GL_COLOR_MATERIAL);
+ gl.glDisable(GLLightingFunc.GL_COLOR_MATERIAL);
}
}
-
+
/**
* Load the model and associated materials, etc
- *
+ *
* @param gl
* @param file
* @return
*/
- private int initialize(GL2 gl, Model model)
+ private int initialize(final GL2 gl, final Model model)
{
if (this.isDebugging)
System.out.println("Initialize Model: " + model.getSource());
-
- int numMaterials = model.getNumberOfMaterials();
-
+
+ final int numMaterials = model.getNumberOfMaterials();
+
if (this.isDebugging && numMaterials > 0) {
- System.out.println("\n Loading " + numMaterials + " Materials:");
+ System.out.println("\n Loading " + numMaterials + " Materials:");
}
-
- String file = model.getSource();
+
+ final String file = model.getSource();
texture = new HashMap<Integer, Texture>();
for (int i=0; i<numMaterials; i++) {
// TODO:DELETE THIS OLD LINE loadTexture(materials.get(i).strFile, i);
// TODO:DELETE THIS OLD LINE materials.get(i).texureId = i;
-
+
String subFileName = "";
-
+
// If this is read from a jar file, then try to find the path relative to the model
int index = file.lastIndexOf('/');
if (index != -1) {
@@ -175,118 +184,118 @@ public class DisplayListRenderer implements iModel3DRenderer { // Else, the file path of the model was not from a jar file, so check maybe it
// was from a local file and get that path.
index = file.lastIndexOf('\\');
-
+
if (index != -1) {
subFileName = file.substring(0,index+1);
}
}
-
+
if (model.getMaterial(i).strFile != null) {
if (this.isDebugging)
- System.out.print(" Material: " + subFileName + model.getMaterial(i).strFile);
-
+ System.out.print(" Material: " + subFileName + model.getMaterial(i).strFile);
+
URL result;
try {
result = ResourceRetriever.getResourceAsUrl(subFileName + model.getMaterial(i).strFile);
- } catch(IOException e) {
+ } catch(final IOException e) {
if (this.isDebugging)
System.err.println(" ... failed");
continue;
}
if (result != null && !result.getPath().endsWith("/") && !result.getPath().endsWith("\\")) {
- loadTexture(result, i);
+ loadTexture(gl.getGLProfile(), result, i);
model.getMaterial(i).textureId = i;
if (this.isDebugging)
System.out.println(" ... done. Texture ID: " + i);
} else if (this.isDebugging) {
System.out.println(" ... failed (no result for material)");
- }
- }
+ }
+ }
}
-
+
if (this.isDebugging && numMaterials > 0) {
- System.out.println(" Load Materials: Done");
+ System.out.println(" Load Materials: Done");
}
-
+
if (this.isDebugging)
System.out.println("\n Generate Lists:");
- int compiledList = listCache.generateList(model, gl, 3);
-
+ final int compiledList = listCache.generateList(model, gl, 3);
+
if (this.isDebugging)
- System.out.println(" Model List");
+ System.out.println(" Model List");
gl.glNewList(compiledList, GL2.GL_COMPILE);
genList(gl, model);
gl.glEndList();
-
+
modelBoundsList = compiledList + 1;
if (this.isDebugging)
- System.out.println(" Boundary List");
+ System.out.println(" Boundary List");
gl.glNewList(modelBoundsList, GL2.GL_COMPILE);
genModelBoundsList(gl, model);
gl.glEndList();
-
+
objectBoundsList = compiledList + 2;
-
+
if (this.isDebugging)
- System.out.println(" Object Boundary List");
+ System.out.println(" Object Boundary List");
gl.glNewList(objectBoundsList, GL2.GL_COMPILE);
genObjectBoundsList(gl, model);
gl.glEndList();
-
+
if (this.isDebugging)
{
System.out.println(" Generate Lists: Done");
System.out.println("Load Model: Done");
}
-
+
return compiledList;
}
-
+
/**
* Load a texture given by the specified URL and assign it to the texture
* id that is passed in.
- *
+ *
* @param url
* @param id
*/
- private void loadTexture(URL url, int id) {
+ private void loadTexture(final GLProfile glp, final URL url, final int id) {
if ( url != null ) {
BufferedImage bufferedImage = null;
try {
bufferedImage = ImageIO.read(url);
- } catch (Exception e) {
+ } catch (final Exception e) {
System.err.println(" ... FAILED loading texture with exception: "+e.getMessage());
return;
}
-
- texture.put(id, AWTTextureIO.newTexture(bufferedImage, true));
+
+ texture.put(id, AWTTextureIO.newTexture(glp, bufferedImage, true));
}
}
-
+
/**
* Generate the model display list
- *
+ *
* @param gl
*/
- private void genList(GL2 gl, Model model) {
+ private void genList(final GL2 gl, final Model model) {
TextureCoords coords;
-
+
for (int i=0; i<model.getNumberOfMeshes(); i++) {
- Mesh tempObj = model.getMesh(i);
-
+ final Mesh tempObj = model.getMesh(i);
+
if (tempObj.numOfFaces == 0) {
System.err.println("Mesh: " +tempObj.name + " has no faces");
continue;
}
-
+
if(tempObj.hasTexture && texture.get(tempObj.materialID) != null) {
- Texture t = texture.get(tempObj.materialID);
-
+ final Texture t = texture.get(tempObj.materialID);
+
// switch to texture mode and push a new matrix on the stack
- gl.glMatrixMode(GL2.GL_TEXTURE);
+ gl.glMatrixMode(GL.GL_TEXTURE);
gl.glPushMatrix();
// check to see if the texture needs flipping
@@ -296,26 +305,26 @@ public class DisplayListRenderer implements iModel3DRenderer { }
// switch to modelview matrix and push a new matrix on the stack
- gl.glMatrixMode(GL2.GL_MODELVIEW);
+ gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
gl.glPushMatrix();
// This is required to repeat textures...because some are not and so only
// part of the model gets filled in....Might be a way to check if this is
// required per object but I'm not sure...would need to research this.
- gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_REPEAT);
- gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_REPEAT);
+ gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT);
+ gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT);
// enable, bind and get texture coordinates
- t.enable();
- t.bind();
+ t.enable(gl);
+ t.bind(gl);
coords = t.getImageTexCoords();
}
-
+
for (int j=0; j<tempObj.numOfFaces; j++) {
// If the object has a texture, then do nothing till later...else
// apply the material property to it.
- if(tempObj.hasTexture) {
+ if(tempObj.hasTexture) {
// nothing
// Has no texture but has a material instead and this material is
@@ -324,14 +333,14 @@ public class DisplayListRenderer implements iModel3DRenderer { // with a FACE and not an OBJECT
} else {
if (tempObj.faces[j].materialID < model.getNumberOfMaterials()) {
- float[] rgba = new float[4];
-
- Material material = model.getMaterial(tempObj.faces[j].materialID);
- gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_DIFFUSE, material.diffuseColor.getRGBComponents(rgba), 0);
- gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT, material.ambientColor.getRGBComponents(rgba), 0);
- gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_SPECULAR, material.specularColor.getRGBComponents(rgba), 0);
- gl.glMaterialf(GL2.GL_FRONT, GL2.GL_SHININESS, material.shininess);
- gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_EMISSION, material.emissive.getRGBComponents(rgba), 0);
+ final float[] rgba = new float[4];
+
+ final Material material = model.getMaterial(tempObj.faces[j].materialID);
+ gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_DIFFUSE, material.diffuseColor.getRGBComponents(rgba), 0);
+ gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT, material.ambientColor.getRGBComponents(rgba), 0);
+ gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_SPECULAR, material.specularColor.getRGBComponents(rgba), 0);
+ gl.glMaterialf(GL.GL_FRONT, GLLightingFunc.GL_SHININESS, material.shininess);
+ gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_EMISSION, material.emissive.getRGBComponents(rgba), 0);
}
}
@@ -346,12 +355,12 @@ public class DisplayListRenderer implements iModel3DRenderer { try {
normalIndex = tempObj.faces[j].normalIndex[whichVertex];
-
+
indexType = 0;
gl.glNormal3f(tempObj.normals[normalIndex].x, tempObj.normals[normalIndex].y, tempObj.normals[normalIndex].z);
if (tempObj.hasTexture) {
- if (tempObj.texCoords != null) {
+ if (tempObj.texCoords != null) {
textureIndex = tempObj.faces[j].coordIndex[whichVertex];
indexType = 1;
gl.glTexCoord2f(tempObj.texCoords[textureIndex].u, tempObj.texCoords[textureIndex].v);
@@ -360,113 +369,113 @@ public class DisplayListRenderer implements iModel3DRenderer { indexType = 2;
gl.glVertex3f(tempObj.vertices[vertexIndex].x, tempObj.vertices[vertexIndex].y, tempObj.vertices[vertexIndex].z);
}
- catch (Exception e) {
+ catch (final Exception e) {
e.printStackTrace();
switch (indexType) {
case 0:
System.err.println("Normal index " + normalIndex + " is out of bounds");
break;
-
+
case 1:
System.err.println("Texture index " + textureIndex + " is out of bounds");
break;
-
+
case 2:
System.err.println("Vertex index " + vertexIndex + " is out of bounds");
break;
}
}
}
- gl.glEnd();
+ gl.glEnd();
}
if (tempObj.hasTexture) {
- Texture t = texture.get(tempObj.materialID);
+ final Texture t = texture.get(tempObj.materialID);
if (t != null)
- t.disable();
-
- gl.glMatrixMode(GL2.GL_TEXTURE);
+ t.disable(gl);
+
+ gl.glMatrixMode(GL.GL_TEXTURE);
gl.glPopMatrix();
- gl.glMatrixMode(GL2.GL_MODELVIEW);
+ gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
gl.glPopMatrix();
}
}
-
+
// Try this clearing of color so it won't use the previous color
gl.glColor3f(1.0f, 1.0f, 1.0f);
}
-
+
/**
- * Render the desired object of the model (specified by an id number of
+ * Render the desired object of the model (specified by an id number of
* the object)
- *
+ *
* @param gl
* @param id
*/
- public void renderBoundsOfObject(GL2 gl, int id, Model model) {
+ public void renderBoundsOfObject(final GL2 gl, final int id, final Model model) {
if (id >=0 && id <= model.getNumberOfMeshes()) {
if (model.getMesh(id).bounds != null) {
drawBounds(gl, model.getMesh(id).bounds);
}
}
}
-
+
/**
- * Draw the boundary of the model (the large box representing the entire
+ * Draw the boundary of the model (the large box representing the entire
* model and not the object in it)
- *
+ *
* @param gLDrawable
*/
- private void genModelBoundsList(GLAutoDrawable gLDrawable, Model model) {
- GL2 gl = gLDrawable.getGL().getGL2();
+ private void genModelBoundsList(final GLAutoDrawable gLDrawable, final Model model) {
+ final GL2 gl = gLDrawable.getGL().getGL2();
drawBounds(gl, model.getBounds());
}
-
+
/**
- * Draw the boundary of the model (the large box representing the entire
+ * Draw the boundary of the model (the large box representing the entire
* model and not the object in it)
- *
+ *
* @param gl
*/
- private void genModelBoundsList(GL2 gl, Model model) {
+ private void genModelBoundsList(final GL2 gl, final Model model) {
drawBounds(gl, model.getBounds());
}
-
+
/**
* Draw the boundaries over all of the objects of the model
*
* @param gLDrawable
*/
- private void genObjectBoundsList(GLAutoDrawable gLDrawable, Model model) {
- GL2 gl = gLDrawable.getGL().getGL2();
+ private void genObjectBoundsList(final GLAutoDrawable gLDrawable, final Model model) {
+ final GL2 gl = gLDrawable.getGL().getGL2();
genObjectBoundsList(gl, model);
- }
-
+ }
+
/**
* Draw the boundaries over all of the objects of the model
- *
+ *
* @param gl
*/
- private void genObjectBoundsList(GL2 gl, Model model) {
+ private void genObjectBoundsList(final GL2 gl, final Model model) {
for (int i=0; i<model.getNumberOfMeshes(); i++) {
if (model.getMesh(i).bounds != null) {
drawBounds(gl, model.getMesh(i).bounds);
}
- }
+ }
}
- /**
- * Draws the bounding box of the object using the max and min extrema
+ /**
+ * Draws the bounding box of the object using the max and min extrema
* points.
*
* @param gl
* @param bounds
*/
- private void drawBounds(GL2 gl, Bounds bounds) {
+ private void drawBounds(final GL2 gl, final Bounds bounds) {
// Front Face
- gl.glBegin(GL2.GL_LINE_LOOP);
+ gl.glBegin(GL.GL_LINE_LOOP);
gl.glVertex3f(bounds.min.x, bounds.min.y, bounds.min.z);
gl.glVertex3f(bounds.max.x, bounds.min.y, bounds.min.z);
gl.glVertex3f(bounds.max.x, bounds.max.y, bounds.min.z);
@@ -474,15 +483,15 @@ public class DisplayListRenderer implements iModel3DRenderer { gl.glEnd();
// Back Face
- gl.glBegin(GL2.GL_LINE_LOOP);
+ gl.glBegin(GL.GL_LINE_LOOP);
gl.glVertex3f(bounds.min.x, bounds.min.y, bounds.max.z);
gl.glVertex3f(bounds.max.x, bounds.min.y, bounds.max.z);
gl.glVertex3f(bounds.max.x, bounds.max.y, bounds.max.z);
gl.glVertex3f(bounds.min.x, bounds.max.y, bounds.max.z);
- gl.glEnd();
+ gl.glEnd();
// Connect the corners between the front and back face.
- gl.glBegin(GL2.GL_LINES);
+ gl.glBegin(GL.GL_LINES);
gl.glVertex3f(bounds.min.x, bounds.min.y, bounds.min.z);
gl.glVertex3f(bounds.min.x, bounds.min.y, bounds.max.z);
@@ -496,29 +505,29 @@ public class DisplayListRenderer implements iModel3DRenderer { gl.glVertex3f(bounds.min.x, bounds.max.y, bounds.max.z);
gl.glEnd();
}
-
+
/**
* Convert an Unsigned byte to integer
- *
+ *
* @param b
* @return
*/
- public int unsignedByteToInt(byte b) {
- return (int) b & 0xFF;
+ public int unsignedByteToInt(final byte b) {
+ return b & 0xFF;
}
-
+
/**
* Convert integer to float
- *
+ *
* @param i
* @return
*/
- public float intToFloat(int i) {
- return (float) i / 255.0f;
+ public float intToFloat(final int i) {
+ return i / 255.0f;
}
-
+
public class DisplayListCache {
- private HashMap <Object, Integer>listCache;
+ private final HashMap <Object, Integer>listCache;
/** Creates a new instance of WWDisplayListCache */
private DisplayListCache() {
@@ -529,37 +538,37 @@ public class DisplayListRenderer implements iModel3DRenderer { listCache.clear();
}
- public int get(Object objID) {
+ public int get(final Object objID) {
if (listCache.containsKey(objID))
return listCache.get(objID);
else
return -1;
}
- public void remove(Object objID, GL2 gl, int howMany) {
- Integer list = listCache.get(objID);
+ public void remove(final Object objID, final GL2 gl, final int howMany) {
+ final Integer list = listCache.get(objID);
if(list != null)
gl.glDeleteLists(list, howMany);
-
+
listCache.remove(objID);
}
/**
- * Returns an integer identifier for an OpenGL display list based on the
- * object being passed in. If the object already has a display list
+ * Returns an integer identifier for an OpenGL display list based on the
+ * object being passed in. If the object already has a display list
* allocated, the existing ID is returned.
*/
- public int generateList(Object objID, GL2 gl, int howMany) {
- Integer list = null;
+ public int generateList(final Object objID, final GL2 gl, final int howMany) {
+ Integer list = null;
list = listCache.get(objID);
if(list == null){
list = new Integer(gl.glGenLists(howMany));
- listCache.put(objID, list);
- }
+ listCache.put(objID, list);
+ }
return list;
- }
+ }
}
}
|