package Renderer; import java.nio.IntBuffer; import java.util.HashMap; import javax.media.opengl.GL; import javax.media.opengl.GL2; import LDraw.Support.LDrawGlobalFlag; import LDraw.Support.MatrixMath; public class LDrawDL implements ILDrawDLHandle { // This turns on normal smoothing. /** * @uml.property name="next_dl" * @uml.associationEnd */ LDrawDL next_dl; // Session "linked list of active dLs." /** * @uml.property name="instance_head" * @uml.associationEnd */ LDrawDLInstance instance_head; // Linked list of instances to draw. /** * @uml.property name="instance_tail" * @uml.associationEnd */ LDrawDLInstance instance_tail; /** * @uml.property name="instance_count" */ int instance_count; /** * @uml.property name="flags" * @uml.associationEnd * qualifier="dl_has_tex:Renderer.LDrawDLT java.lang.Boolean" */ HashMap<LDrawDLT, Boolean> flags; // See flags defs above. /** * @uml.property name="geo_vbo" */ IntBuffer geo_vbo; // Single VBO containing all geometry in the DL. // IntBuffer geo_vao; // Single VAO containing all geometry in the DL. // public ByteBuffer byteBufferForVertex; /** * @uml.property name="idx_vbo" */ IntBuffer idx_vbo; // Single VBO containing all mesh indices. /** * @uml.property name="tex_count" */ int tex_count; // Number of per-textures; untex case is always first if // present. /** * @uml.property name="texes" * @uml.associationEnd multiplicity="(0 -1)" */ LDrawDLPerTex texes[]; // Variable size array of textures - DL is allocated // larger as needed. public LDrawDL(int total_texes) { next_dl = null; instance_head = instance_tail = null; instance_count = 0; texes = new LDrawDLPerTex[total_texes]; for (int i = 0; i < total_texes; i++) texes[i] = new LDrawDLPerTex(); geo_vbo = IntBuffer.allocate(1); // geo_vao = IntBuffer.allocate(1); idx_vbo = IntBuffer.allocate(1); flags = new HashMap<LDrawDLT, Boolean>(); flags.put(LDrawDLT.dl_has_tex, false); } // ========== LDrawDLDraw // ========================================================= // // Purpose: Draw a DL, or save it for later drawing. // // Notes: This routine takes all of the current 'state' and draws or records // an instance. // // Pass draw_now as true to FORCE immediate drawing and disable all of // the instancing/sorting stuff. This is needed if there is extra GL2.GL // state like polygon offset that must be used now that isn't recorded // by this API. // // ================================================================================ public void draw(GL2 gl2, LDrawDLSession session, LDrawTextureSpec spec, float cur_color[], float cmp_color[], float transform[], boolean draw_now) { // IMMEDIATE MODE DRAW CASE! If we get here, we are going to draw this // DL right now at this // position. // Push current transform & color into attribute state. int i; for (i = 0; i < 4; ++i) gl2.glVertexAttrib4f(AttributeT.attr_transform_x.getValue() + i, transform[i], transform[4 + i], transform[8 + i], transform[12 + i]); gl2.glVertexAttrib4fv(AttributeT.attr_color_current.getValue(), cur_color, 0); gl2.glVertexAttrib4fv(AttributeT.attr_color_compliment.getValue(), cmp_color, 0); assert (tex_count > 0); // Bind our DL VBO and set up ptrs. gl2.glBindBuffer(GL2.GL_ARRAY_BUFFER, geo_vbo.get(0)); if (LDrawGlobalFlag.WANT_SMOOTH != false) { gl2.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, idx_vbo.get(0)); } gl2.glVertexAttribPointer(AttributeT.attr_position.getValue(), 3, GL2.GL_FLOAT, false, LDrawDisplayList.VERT_STRIDE * Float.SIZE / 8, 0); gl2.glVertexAttribPointer(AttributeT.attr_normal.getValue(), 3, GL2.GL_FLOAT, false, LDrawDisplayList.VERT_STRIDE * Float.SIZE / 8, 3 * Float.SIZE / 8); gl2.glVertexAttribPointer(AttributeT.attr_color.getValue(), 4, GL2.GL_FLOAT, false, LDrawDisplayList.VERT_STRIDE * Float.SIZE / 8, 6 * Float.SIZE / 8); LDrawDLPerTex tptr = texes[0]; int tptr_index = 0; if (tex_count == 1 && tptr.spec.tex_obj == 0 && (spec == null || spec.tex_obj == 0)) { // Special case: one untextured mesh - just draw. if (LDrawGlobalFlag.WANT_SMOOTH != false) { if (tptr.tri_count != 0) gl2.glDrawElements(GL2.GL_TRIANGLES, tptr.tri_count, GL2.GL_UNSIGNED_INT, tptr.tri_off * Float.SIZE / 8); if (tptr.quad_count != 0) gl2.glDrawElements(GL2.GL_QUADS, tptr.quad_count, GL2.GL_UNSIGNED_INT, tptr.quad_off * Float.SIZE / 8); if (tptr.line_count != 0) gl2.glDrawElements(GL2.GL_LINES, tptr.line_count, GL2.GL_UNSIGNED_INT, tptr.line_off * Float.SIZE / 8); } } else { // Textured case - for each texture set up the DL texture (or // current // texture if none), then draw. int t; for (t = 0; t < tex_count; ++t, tptr = texes[++tptr_index]) { if (tptr.spec.tex_obj != 0) { LDrawDisplayList.setup_tex_spec(gl2, tptr.spec); } else LDrawDisplayList.setup_tex_spec(gl2, spec); if (LDrawGlobalFlag.WANT_SMOOTH != false) { if (tptr.tri_count != 0) gl2.glDrawElements(GL2.GL_TRIANGLES, tptr.tri_count, GL2.GL_UNSIGNED_INT, tptr.tri_off); if (tptr.quad_count != 0) gl2.glDrawElements(GL2.GL_QUADS, tptr.quad_count, GL2.GL_UNSIGNED_INT, tptr.quad_off); if (tptr.line_count != 0) gl2.glDrawElements(GL2.GL_LINES, tptr.line_count, GL2.GL_UNSIGNED_INT, tptr.line_off); } } LDrawDisplayList.setup_tex_spec(gl2, spec); } }// end LDrawDLDraw /** * @return * @uml.property name="next_dl" */ public LDrawDL getNext() { return next_dl; } /** * @param next_dl * @uml.property name="next_dl" */ public void setNext(LDrawDL next_dl) { this.next_dl = next_dl; } /** * @return * @uml.property name="instance_head" */ public LDrawDLInstance getInstance_head() { return instance_head; } /** * @param instance_head * @uml.property name="instance_head" */ public void setInstance_head(LDrawDLInstance instance_head) { this.instance_head = instance_head; } /** * @return * @uml.property name="instance_tail" */ public LDrawDLInstance getInstance_tail() { return instance_tail; } /** * @param instance_tail * @uml.property name="instance_tail" */ public void setInstance_tail(LDrawDLInstance instance_tail) { this.instance_tail = instance_tail; } /** * @return * @uml.property name="instance_count" */ public int getInstance_count() { return instance_count; } /** * @param instance_count * @uml.property name="instance_count" */ public void setInstance_count(int instance_count) { this.instance_count = instance_count; } public HashMap<LDrawDLT, Boolean> getFlags() { return flags; } public void setFlags(HashMap<LDrawDLT, Boolean> flags) { this.flags.putAll(flags); } /** * @return * @uml.property name="geo_vbo" */ public IntBuffer getGeo_vbo() { return geo_vbo; } /** * @param geo_vbo * @uml.property name="geo_vbo" */ public void setGeo_vbo(IntBuffer geo_vbo) { this.geo_vbo = geo_vbo; } /** * @return * @uml.property name="idx_vbo" */ public IntBuffer getIdx_vbo() { return idx_vbo; } /** * @param idx_vbo * @uml.property name="idx_vbo" */ public void setIdx_vbo(IntBuffer idx_vbo) { this.idx_vbo = idx_vbo; } /** * @return * @uml.property name="tex_count" */ public int getTex_count() { return tex_count; } /** * @param tex_count * @uml.property name="tex_count" */ public void setTex_count(int tex_count) { this.tex_count = tex_count; } /** * @return * @uml.property name="texes" */ public LDrawDLPerTex[] getTexes() { return texes; } /** * @param texes * @uml.property name="texes" */ public void setTexes(LDrawDLPerTex[] texes) { this.texes = texes; } // ========== LDrawDLDestroy // ====================================================== // // Purpose: free a display list - release GL2.GL and system memory. // // ================================================================================ public void destroy(GL2 gl2) { if (instance_head != null) { // Special case: if our DL is destroyed WHILE a session is using it // for // deferred drawing, we do NOT destroy it - we mark it for // destruction // later and the session nukes it. This is needed for the case where // client code creates a DL, draws it, and immediately destroys it, // as // a silly way to get 'immediate' drawing. In this case, the session // may have intentionally deferred the DL. flags.put(LDrawDLT.dl_needs_destroy, true); ; return; } // Make sure that no instances from a session are queued to this list; // if we // are in Q and run now, we'll cause seg faults later. This assert hits // when: (1) we build a temp DL and don't mark it as temp or (2) we for // some // reason inval a DL mid-draw, which is usually a sign of coding error. assert (instance_head == null); if (LDrawGlobalFlag.WANT_SMOOTH != false) { gl2.glDeleteBuffers(1, idx_vbo); } gl2.glDeleteBuffers(1, geo_vbo); // gl2.glDeleteVertexArrays(1, geo_vao); }// end LDrawDLDestroy }